Oops!

Attached updated code uses ListCtrl->GetItemRect to determine correct offset when control is scrolled.

Cheers

Mark

On 05/03/2013 20:14, Dave Hayes wrote:
On 02/04/13 19:45, Mark Dootson wrote:
Hi,

A small update to previous code. On wxGTK EVT_LIST_ITEM_RIGHT_CLICK
events are generated even if a right click in the wxListCtrl is not on
an item. Amended attachment handles this.


I've run into a bug with your implementation.

If you add enough columns to invoke the horizontal scrollbar, this
breaks what you wrote. Instead, columns will be reported with 0 being
the visible scrolled column, which is not the actual column.

Googling around a bit seems to indicate that it's impossible to get a
scroll event from a ListCtrl at 2.8. So how would I detect that the
ListCtrl is scrolled horizontally?
#########################################################################################
# Description:  wxListCtrl Test
# Created       Mon Feb 04 15:01:53 2013
# svn id        $Id:$
# Copyright:    Copyright (c) 2013 Mark Dootson
# Licence:      This program is free software; you can redistribute it 
#               and/or modify it under the same terms as Perl itself
#########################################################################################

package MainWindow;
use strict;
use warnings;
use Wx qw( :id :misc :window :sizer :panel :listctrl );
use base qw( Wx::Frame );
use Wx::Event qw(
    EVT_LIST_ITEM_SELECTED EVT_LIST_ITEM_DESELECTED
    EVT_LIST_ITEM_ACTIVATED EVT_LIST_ITEM_FOCUSED
    EVT_LIST_ITEM_RIGHT_CLICK 
);


sub new {
    my $class = shift;
    my $self = $class->SUPER::new( @_ );
    
    my $mainpanel = Wx::Panel->new($self, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxBORDER_NONE );
    my $list = Wx::ListCtrl->new($mainpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL  );
    my $mainsizer = Wx::BoxSizer->new(wxVERTICAL);
    my $panelsizer = Wx::BoxSizer->new(wxVERTICAL);
    
    $panelsizer->Add($list,1,wxALL|wxEXPAND, 0);
    $mainpanel->SetSizer($panelsizer);
    $mainsizer->Add($mainpanel,1,wxALL|wxEXPAND, 0);
    $self->SetSizer($mainsizer);
    
    for (my $i = 0; $i < 9; $i++) {
        $list->InsertColumn($i, qq(Col $i), wxLIST_FORMAT_LEFT, 100);
    }
    
    for (my $i = 0; $i < 40; $i++) {
        $list->InsertStringItem($i, qq(R${i}C0));
        for(my $n = 1; $n < 9; $n++ ) {
            $list->SetItem($i, $n, qq(R${i}C${n}));
        }
    }
    
    EVT_LIST_ITEM_SELECTED($self, $list, \&OnItemSelected);
    EVT_LIST_ITEM_DESELECTED($self, $list, \&OnItemDeselected);
    EVT_LIST_ITEM_ACTIVATED($self, $list, \&OnItemActivated);
    EVT_LIST_ITEM_FOCUSED($self, $list, \&OnItemFocused);
    EVT_LIST_ITEM_RIGHT_CLICK($self, $list, \&OnItemRightClick);
    
    return $self;
}

sub OnItemSelected {
    my($self, $event) = @_;
    $event->Skip(1);
    
    print q(EVT_LIST_ITEM_SELECTED) . qq(\n);
    
}

sub OnItemDeselected {
    my($self, $event) = @_;
    $event->Skip(1);
    
    print q(EVT_LIST_ITEM_DESELECTED) . qq(\n);
}

sub OnItemActivated {
    my($self, $event) = @_;
    $event->Skip(1);
    
    print q(EVT_LIST_ITEM_ACTIVATED) . qq(\n);
}

sub OnItemFocused {
    my($self, $event) = @_;
    $event->Skip(1);
    
    print q(EVT_LIST_ITEM_FOCUSED) . qq(\n);
}

sub OnItemRightClick {
    my($self, $event) = @_;
    $event->Skip(1);
    print q(EVT_LIST_ITEM_RIGHT_CLICK) . qq(\n);
    
    my $listctrl  = $event->GetEventObject;
    my $point = $event->GetPoint();
    
    my ($itemindex, $flags, $subindex) = $listctrl->HitTest($point);
    
    # return if not valid $itemindex;
    return if (!defined($itemindex) || $itemindex == -1 );
    
    if( !Wx::wxMSW() ) {
        # $subindex only populated on wxMSW
        $subindex = $self->_get_generic_subitem( $itemindex, $listctrl, $point );
    }
    
    print qq($itemindex, $flags, $subindex\n);
    my $text = $listctrl->GetItem($itemindex, $subindex)->GetText;
    print qq(Right clicked text: $text\n);
}

sub _get_generic_subitem {
    my($self, $itemindex, $listctrl, $point) = @_;
    
    # iterate through columms and check if $point->x is within that column width
    
    # offset for scrolled content
    my $offsetrect = $listctrl->GetItemRect($itemindex);
    my $left = $offsetrect->x;
    
    for(my $i = 0; $i < $listctrl->GetColumnCount; $i ++) {
        my $right = $left + $listctrl->GetColumnWidth($i);
        if($point->x >= $left && $point->x <= $right) {
            return $i;
        } else {
            $left = $right + 1;
        }
    }
    
    Wx::LogError('Could not determine column in right click');
    return 0;
}


package Application;
use strict;
use warnings;
use Wx;

use base qw( Wx::App );


sub OnInit {
    my $self = shift;
    
    my $mwin = MainWindow->new(undef, -1, 'Test wxListCtrl' );
    
    $self->SetTopWindow($mwin);
    $mwin->Show(1);
}

package main;

my $app = Application->new;
$app->MainLoop;


1;

Reply via email to