Sign up

Button Without Subclassing?

I've run into something that has me scratching my head. The following code, based on a number of similar examples, doesn't work. I'm starting to think I can only hook an event to a button if it's subclassed.

Can anyone set me straight?

import gtk.MainWindow;
import gtk.Main;
import gtk.Button;
import gtk.Widget;
import gdk.Event;

void main(string[] args)
{
	Main.init(args);
	MainWindow myAppWin = new MainWindow("Test Rig");

	Button myButt = new Button();
	myButt.setLabel("My Butt");
	
	myButt.addOnButtonRelease(&quitApp);
	
	myAppWin.add(myButt);
	
	myAppWin.addOnDestroy(delegate void(Widget w) { quitApp(); });
	myAppWin.showAll();
	Main.run();
	
} // main()

void quitApp(Event event, Widget widget)
{
	writeln("Quit, eh");
	
	Main.quit();
	
	return(true);
} // quitApp()

Re: Button Without Subclassing?

On 22-12-2018 13:34, Ron Tarrant wrote:

I've run into something that has me scratching my head. The following code, based on a number of similar examples, doesn't work. I'm starting to think I can only hook an event to a button if it's subclassed.

Can anyone set me straight?

......

The main issue is that the quitApp function is a static function so
taking it's address will return a function pointer and not a delegate.

There are a few ways to go about fixing that:

  • use std.functional.toDelegate to turn it into a delegate.
  • Put the function inside main as a nested function, it will be a
    delegate in that case.
  • Wrap the call in a anonymous delegate as with addOnDestroy.
  • Use gobject.Signals.connect which also accepts function pointers.

There were two smaller issues with the example:

  • The return type of quitApp should be bool.
  • Missing std.stdio import.
import gtk.MainWindow;
import gtk.Main;
import gtk.Button;
import gtk.Widget;
import gdk.Event;

import std.stdio;
import std.functional;

void main(string[] args)
{
	Main.init(args);
	MainWindow myAppWin = new MainWindow("Test Rig");

	Button myButt = new Button();
	myButt.setLabel("My Butt");
	
	myButt.addOnButtonRelease(toDelegate(&quitApp));
	
	myAppWin.add(myButt);
	
	myAppWin.addOnDestroy(delegate void(Widget w) { quitApp(null, null); });
	myAppWin.showAll();
	Main.run();
	
} // main()

bool quitApp(Event event, Widget widget)
{
	writeln("Quit, eh");
	
	Main.quit();
	
	return(true);
} // quitApp()

Re: Button Without Subclassing?

On Sun, 23 Dec 2018 13:09:39 +0100, Mike Wey wrote:

On 22-12-2018 13:34, Ron Tarrant wrote:
The main issue is that the quitApp function is a static function so
taking it's address will return a function pointer and not a delegate.

There are a few ways to go about fixing that:

  • use std.functional.toDelegate to turn it into a delegate.
  • Put the function inside main as a nested function, it will be a

delegate in that case.

  • Wrap the call in a anonymous delegate as with addOnDestroy.
  • Use gobject.Signals.connect which also accepts function pointers.

There were two smaller issues with the example:

  • The return type of quitApp should be bool.
  • Missing std.stdio import.

Thanks for all that, Mike. After posting my question, I kept on digging and figured out the difference between the two types of callback. I think I'm now well on my way toward understanding this stuff:

import std.stdio;
import gtk.MainWindow;
import gtk.Main;
import gtk.Widget;
import gtk.Layout;
import gtk.Button;
import gdk.Event;

void main(string[] args)
{
	Main.init(args);
	TestRigWindow myTestRig = new TestRigWindow("Test Rig");
	myTestRig.showAll();
	Main.run();
	
} // main()


class TestRigWindow : MainWindow
{
	this(string title)
	{
		// window
		super(title);
		addOnDestroy(delegate void(Widget w) { quitApp(); } );
		
		auto myButton = new MyButt("Button Name");
		auto myOtherButton = new MyOtherButt("Other Button Name");
		
		// layout
		auto myLayout = new MyLayout(myButton, myOtherButton);
		add(myLayout);
		
	} // this() CONSTRUCTOR
	
	
	void quitApp()
	{
		writeln("Bye.");
		Main.quit();
		
	} // quitApp()

} // class myAppWindow


class MyLayout : Layout
{
	this(MyButt myButton, MyOtherButt otherButton)
	{
		super(null, null);
		put(myButton, 10, 20);
		put(otherButton, 10, 60);
		
	} // this()
	
} // class MyLayout


class MyButt : Button
{
	this(string labelText)
	{
		super(labelText);
		addOnButtonRelease(&doSomething);
		
	} // this()
	
	
	bool doSomething(Event e, Widget w)
	{
		writeln("Something was done.");
		
		return(true);
		
	} // doSomething()

} // class MyButt


class MyOtherButt : Button
{
	this(string labelText)
	{
		super(labelText);
		string message = "Something other than that was done.";
		addOnClicked(delegate void(_) { doSomething(message); } );
		
	} // this()
	
	
	void doSomething(string messageText)
	{
		writeln(messageText);
		
	} // doSomething()

} // class MyButt