[Kde-perl] Why isn't this easy? implementing File->New

darrik darrik at mythofbutterfly.com
Wed Aug 2 21:25:12 CEST 2006


Unless you need to access the window later programmatically (aside from 
slots and signals), there's no need to keep a window list.

Using $myApplication->setMainWidget($firstWindow) in your script will 
kill the exec() loop when you close the first window.

Omitting this step keeps the other windows open after the first window 
closes, even without any perl references to the new windows.  The only 
downfall of this method is that the app doesn't exit the exec() loop 
when all windows are closed.  Perhaps a counter that increments when a 
window is created and decrements when it is closed, closing the app when 
it reaches 0?

The applicable parts of my test scripts are as follows:

# test.pl
use strict;
use warnings;

use Qt;
use MyView;

my $qApp=Qt::Application(\@ARGV);

my $mw=MyView();

# with this line, closing the first window closes the app
# $qApp->setMainWidget($mw);

$mw->show();

exit($qApp->exec());

# MyView.pm

sub NEW {
     print("MyView::NEW(@_)\n");
     shift->SUPER::NEW(@_);
     my $action=Qt::Action(
         "newfile",
         Qt::KeySequence("ALT+N"),
         this,
         "filenew"
     );
     this->connect($action,SIGNAL("activated()"),this,SLOT("fileNew()"));
}

sub fileNew {
     print("MyView::fileNew(@_)\n");
     MyView(this)->show();
}

Andrew Snyder wrote:
> I'd go with a package scoped variable. Any reason why this wouldn't work?
> 
> package MyView;
> our %window_list;
> ...
> ...
> sub NEW {
> ...
>   $window_list{$self}++;
> ...
> }
> 
> sub DESTROY
> {
>    my $self = shift;
>    if (defined $window_list{$self})
>    {
>       delete $window_list{$self};
>    }
> ...
> }
> 
> 
> 
> 
> On Wednesday 02 August 2006 12:38, Joe Carlson wrote:
>> Darrik and Ashley,
>>
>> Thanks for the info. I appreciate the 'garbage collection done him
>> wrong' advice. This is definitely it.
>>
>> But I have now a comment or two about these methods. It seems like all
>> of these are ways to create references to the newly created top-level
>> windows to keep the reference count from going to zero and getting
>> destroyed. But it seems to me that this needs to be done at a global (or
>> application) level. If I keep a list of the new windows I've created
>> within the first window, what happens when I close the first window? In
>> trying out different things, I'm seeing that the created windows also
>> close. (Of course maybe it's some quirk about how I've scoped
>> variables...) There are some cases where closing the creating window
>> also closes the created, but this isn't what I'm looking for. I was
>> trying out Darrik's hash-the-reference approach and seeing this
>> behavior. (In addition, it seemed to me that if I opened a third window
>> after opening one from from the first, the second window closed. Again,
>> maybe that was a scoping issue.)
>>
>> What I see as the simplest way to beat the garbage collection is to
>> simple put a self reference in the class
>>
>> package MyView;
>> ...
>> use Qt::attributes qw(selfReference ...);
>> ...
>> sub NEW {
>> ...
>>   selfReference = this;
>> ...
>> and so on.
>>
>> In my playing around, this gives me all the right behavior. But if
>> future collectors get more clever and see that this is a circular
>> reference all bets are off. The only iron clad way to keep the reference
>> is to make a list a global scope
>>
>> push @main::windowList, $newWindow;
>>
>> But now here's the thing: this now is reproducing the C++ behavior,
>> warts and all. The C++ code is simple, I just 'new' me up a main window
>> and call show on it. And we've manage to make it this simple in the perl
>> code. But we've just created a memory leak since we've made no
>> allowances for freeing memory after the created windows are closed.
>>
>> If I use the self-reference trick, then I need to reset this before
>> calling close:
>>
>> sub processFileMenu {
>> ...
>>   if ($option == FILECLOSE) {
>>     selfReference = '';
>>     this->close();
>>   }
>> ...
>>
>> I've been testing this out with print's in the module's DESTROY method
>> and things seem to be cleaning up properly. I'm going to try this out.
>> The only other option I can think of is to use the application level
>> list and emit signal when there is a request to close the top level
>> window and have the application deal with removing the reference from
>> the list.
>>
>> Thanks,
>>
>> Joe
>>
>> On Tue, 2006-08-01 at 23:12 -0700, Ashley Winters wrote:
>>> --- darrik <darrik at mythofbutterfly.com> wrote:
>>>> Ashley Winters wrote:
>>>>> use strict;
>>>>> use Qt;     # use Qt in EVERY package! It declares 'this', and does
>>>>> other use-strict-happy things
>>>>> use MyView;
>>>>> sub processFileMenu {
>>>>> 	if ($option==FILENEW) {
>>>>> 		MyView(this)->show;
>>>>> 	}
>>>>> }
>>>> You're not storing a perl reference to the new window anywhere.  What
>>>>
>>>> happens when you want to access that window from the parent later?
>>> Ahh, in that case you want to store it as a member variable. If, for
>>> example, we wanted to populate the Window menu with the list of windows
>>> opened with File->New or something...
>>>
>>> package YourClass;
>>> use strict;
>>> use Qt;
>>> use Qt::isa qw(Qt::Widget);
>>> use Qt::attributes qw(windows);    # declare a member variable
>>> use MyView;
>>>
>>> sub NEW {
>>>     # standard preamble
>>>
>>>     windows = [];    # initialize as an array
>>> }
>>>
>>> sub processFileMenu {
>>> 	if ($option==FILENEW) {
>>> 		my $viewer = MyView(this);
>>> 		$viewer->show;
>>> 		push @{ windows }, $viewer;
>>> 	}
>>> }
>>>
>>>> This is more evident when you subclass a container widget that has
>>>> child
>>>> controls.  For instance:
>>> I'll make the edits inline...
>>>
>>>> use strict;
>>>>
>>>> package MyWidget;
>>>>
>>>> use Qt;
>>>> use Qt::isa qw( Qt::Widget );
>>> use Qt::attributes qw( lbl );
>>>
>>>> sub NEW {
>>>>    # irrelevant method arguments left out for brevity :P
>>>>
>>>>    my $class=shift;
>>>>    my $parent=shift;
>>>>    shift->SUPER::NEW($parent);
>>>>    my $layout=Qt::HBoxLayout(this);
>>> #>    my $lbl=Qt::Label("label",this);
>>> #>    $layout->addWidget($lbl);
>>>
>>>     # instead
>>>     lbl = Qt::Label("label",this);
>>>     $layout->addWidget(lbl);
>>>
>>>> }
>>>>
>>>> sub changeChildLabel {
>>>>    # how do you access $lbl here?
>>>     lbl->setText("Qt::attributes");
>>>
>>>> }
>>>>
>>>>
>>>> This part has me confused.  Storing $lbl in a package variable
>>>> doesn't
>>>> work if you instantiate several MyWidget's.  I've been using
>>>> workarounds
>>>> that are inelegant, so a pointer to the *proper* way to do this would
>>>> be
>>>> immensely appreciated.
>>> Sure. Keep in mind that the 'this' function/variable/keyword thing is,
>>> in fact, a hash. You're free to store things in it, like so:
>>>
>>> this->{'lbl'} = Qt::Label(...);
>>>
>>> In fact, that's all the Qt::attributes pragma does, is setup that
>>> shortcut. It automatically creates a lbl() function which returns
>>> this->{'lbl'}, in a way that lets you assign to it (as an lvalue).
>>>
>>> That's the technical side, at least. For more of a tutorial, read this:
>>>
>>> http://perlqt.sourceforge.net/dist/current/doc/en/index.html#using_attrib
>>> utes
>>>
>>> - Ashley Winters
>>>
>>> __________________________________________________
>>> Do You Yahoo!?
>>> Tired of spam?  Yahoo! Mail has the best spam protection around
>>> http://mail.yahoo.com
>>> _______________________________________________
>>> Kde-perl mailing list
>>> Kde-perl at kde.org
>>> https://mail.kde.org/mailman/listinfo/kde-perl
>> _______________________________________________
>> Kde-perl mailing list
>> Kde-perl at kde.org
>> https://mail.kde.org/mailman/listinfo/kde-perl
> 



More information about the Kde-perl mailing list