Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[AHK_L][Alpha]CGUI - Object-Oriented GUIS!


  • Please log in to reply
151 replies to this topic
fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
I have implemented FocusEnter, FocusLeave and Validate for all fitting controls/situations now. Unfortunately some controls like Hotkey control don't support it.

I wonder if I should support Validate callbacks for controls like ListView or TreeView? Right now the callback functions for Edit and ComboBox simply return the correct value as text but this is impossible for controls containing more advanced data. These controls could modify their contents manually in the callback function though.

zzzooo10
  • Members
  • 237 posts
  • Last active: Apr 14 2015 01:57 AM
  • Joined: 19 Dec 2010
Thanks for the help fragman, I really like this lib. It makes Guis in AutoHotkey a lot better.

Edit:
When using a Listview and a custom menu I seem to get a lot of lag.
If I right click one item in the listview and then right click the other it seems to freeze
Is there anyway to fix this?
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#Persistent
#SingleInstance, Force
; #NoTrayIcon

SetBatchLines, -1
ListLines, Off
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

gui := new Test() 
#include <CGUI> 

Class Test Extends CGUI 
{ 
   __New() 
   { 
      Base.__New() ;init CGUI 
      this.Add("ListView", "randomListView", "", "Keys") 
      
      
        Menu, LButton, Add, Down, MouseEvent 
        Menu, LButton, Add, Up, MouseEvent 
        Menu, LButton, Add, Click, MouseEvent 
        
        Menu, RButton, Add, Down, MouseEvent 
        Menu, RButton, Add, Up, MouseEvent 
        Menu, RButton, Add, Click, MouseEvent 
        
        Menu, MButton, Add, Down, MouseEvent 
        Menu, MButton, Add, Up, MouseEvent 
        Menu, MButton, Add, Click, MouseEvent 
        
        Menu, MouseEvents, Add, Left Button, :LButton
        Menu, MouseEvents, Add, Right Button, :RButton
        Menu, MouseEvents, Add, Middle Button, :MButton
        
        Menu, Macro, Add, Insert Mouse Event, :MouseEvents, P100
        
        Menu, Macro, Add, Edit, Edit
        Menu, Macro, Add, Insert Delay, InsertDelay
        Menu, Macro, Add, Delete, Delete
      
      this.randomListView.Items.Add("", "Right Click me!")
      this.randomListView.Items.Add("", "No, click me!")
      
      this.Title := "Test" 
      this.DestroyOnClose := true ;By Setting this the window will destroy itself when the user cloeses it 
      this.Show() 
   } 

    randomListView_RightClick(RowIndex) 
    { 
        Menu, Macro, Show
    } 
    
   ;Called when the window was destroyed (e.g. closed here) 
   PreClose() 
   { 
      ExitApp 
   } 
} 

Test_randomListView: 
CGUI.HandleEvent()
return

MouseEvent:
Delete:
InsertDelay:
Edit:
return


fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
I'll take a look later. On another note, PreClose is called before the window is closed. That means that the window is neither closed nor destroyed in this function. If you have DestroyOnClose activated, it will destroy itself after the call to PreClose. After destruction PostDestroy is called.

Edit: I just tried to execute it and I can confirm that the script halts until it gets reactivated. I'll have to do some debugging to see more, but I think I read about a similar behavior some days before on the forum, does anyone remember?

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Here is the thread I meant, doesn't reveal anything apart from showing the same symptoms: <!-- m -->http://www.autohotke...pic.php?t=76530<!-- m -->

Edit: Simple Workaround (but no fix yet...):
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases. 
#Persistent 
#SingleInstance, Force 
; #NoTrayIcon 

SetBatchLines, -1 
ListLines, Off 
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory. 

gui := new Test() 
#include <CGUI> 

Class Test Extends CGUI 
{ 
   __New() 
   { 
      Base.__New() ;init CGUI 
      this.Add("ListView", "randomListView", "", "Keys") 
      this.Add("Button", "btnTest", "", "Test")
      
        Menu, LButton, Add, Down, MouseEvent 
        Menu, LButton, Add, Up, MouseEvent 
        Menu, LButton, Add, Click, MouseEvent 
        
        Menu, RButton, Add, Down, MouseEvent 
        Menu, RButton, Add, Up, MouseEvent 
        Menu, RButton, Add, Click, MouseEvent 
        
        Menu, MButton, Add, Down, MouseEvent 
        Menu, MButton, Add, Up, MouseEvent 
        Menu, MButton, Add, Click, MouseEvent 
        
        Menu, MouseEvents, Add, Left Button, :LButton 
        Menu, MouseEvents, Add, Right Button, :RButton 
        Menu, MouseEvents, Add, Middle Button, :MButton 
        
        Menu, Macro, Add, Insert Mouse Event, :MouseEvents, P100 
        
        Menu, Macro, Add, Edit, Edit 
        Menu, Macro, Add, Insert Delay, InsertDelay 
        Menu, Macro, Add, Delete, Delete 
      
      this.randomListView.Items.Add("", "Right Click me!") 
      this.randomListView.Items.Add("", "No, click me!") 
      
      this.Title := "Test" 
      this.DestroyOnClose := true ;By Setting this the window will destroy itself when the user cloeses it 
      this.Show() 
   } 

    ContextMenu()
    {
		if(this.ActiveControl.Name = "randomListView") ;Also works if other controls like the button were focused before.
			Menu, Macro, Show
    } 
    
   ;Called when the window was destroyed (e.g. closed here) 
   PreClose() 
   { 
      ExitApp 
   } 
} 

Test_randomListView: 
CGUI.HandleEvent() 
return 

MouseEvent: 
Delete: 
InsertDelay: 
Edit: 
return


fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Fixed. My latest commit is online. I didn't turn off Critical in the code that is called from the g-label, because I assumed that it would be turned off again after this thread finishes, but it turns out I was wrong. Could anyone explain what really happens there?

The menu itself gets shown in another thread that is started by a timer.

zzzooo10
  • Members
  • 237 posts
  • Last active: Apr 14 2015 01:57 AM
  • Joined: 19 Dec 2010
Thanks a lot fragman for getting the context menu to work, but yet again I have another problem. This time the Insert command seems to be acting funny.
Its easier to show then describe, but when ever I try to insert a column everything seems to get mixed up in the listview.
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases. 
#Persistent 
#SingleInstance, Force 
; #NoTrayIcon 

SetBatchLines, -1 
ListLines, Off 
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory. 

gui := new Test() 
#include <CGUI> 

Class Test Extends CGUI 
{ 
   __New() 
   { 
      Base.__New() ;init CGUI 
      this.Add("ListView", "randomListView", "", "Text") 
      
      this.randomListView.Items.Add("", "Right Click me!") 
      this.randomListView.Items.Add("", "No, click me!") 
      
      Loop % this.randomListView.Items.Count ; Get all of the cols in the listview.
        listviewText .= this.randomListView.Items[A_Index][1] . "`n"
      MsgBox % listviewText
      listviewText := ""
      
      this.randomListView.Items.Insert(1, "", "Left Click me!") 
      
      this.Title := "Test" 
      this.DestroyOnClose := true ;By Setting this the window will destroy itself when the user cloeses it 
      this.Show() 

      Loop % this.randomListView.Items.Count ; Not returning Right Click me.
        listviewText .= this.randomListView.Items[A_Index][1] . "`n"
      MsgBox % listviewText
   }
   
   randomListView_Click(RowIndex)
   {
    MsgBox % this.randomListView.Items[RowIndex][1] ; Provides different text than what is shown in the listview
   }
    
   ;Called when the window was destroyed (e.g. closed here) 
   PreClose() 
   { 
      ExitApp 
   } 
} 

Test_randomListView: 
CGUI.HandleEvent() 
return
Edit:
I ended up using ControlGet to get the text from the listview.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I didn't turn off Critical in the code that is called from the g-label, because I assumed that it would be turned off again after this thread finishes, but it turns out I was wrong.

You thought you were wrong, but you were mistaken. Critical is thread-specific. However, if a message is received before the critical thread finishes, the message may be discarded or buffered instead of launching a new thread. (I haven't looked into your g-label problem, so this might not be relevant.)

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009

I didn't turn off Critical in the code that is called from the g-label, because I assumed that it would be turned off again after this thread finishes, but it turns out I was wrong.

You thought you were wrong, but you were mistaken. Critical is thread-specific. However, if a message is received before the critical thread finishes, the message may be discarded or buffered instead of launching a new thread. (I haven't looked into your g-label problem, so this might not be relevant.)


Yes that's mostly what I believed. Rereading the Critical section makes me believe it might be because I am listening to WM_NOTIFY and WM_COMMAND which are below 0x312:

A critical thread will be interrupted in emergencies. Emergencies consist of: 1) the OnExit subroutine; 2) any OnMessage() function that monitors a message number less than 0x312 (or a callback triggered by such a message); and 3) any callback indirectly triggered by the critical thread itself (e.g. via SendMessage or DllCall). To avoid these interruptions, temporarily disable such functions.



zzzooo10
  • Members
  • 237 posts
  • Last active: Apr 14 2015 01:57 AM
  • Joined: 19 Dec 2010
On line 250 in CGUI.ahk you miss spelled "Menuname" as "Menname" preventing the menu function from working, and for the tab control how do you change which controls belong to each tab?

Edit:
I'm also having some trouble with the dropdownlist.
The SelectionChanged function isn't getting called when I select an item in the DropDownList and the Add function does't seem to be working correctly either.
gui := new Gui()
#include <CGUI>
Class Gui Extends CGUI
{

	__New()
	{
		Base.__New() ;init CGUI
        this.Add("DropDownList", "dropDown", "w430 h400", "a|b")
        
        ; Trying to have the DropDownList read c|d instead of a|b
        this.dropDown.Items.Add("c", 1)
        this.dropDown.Items.Add("d", 2)
        
		this.Title := "Gui"
        this.Show()
	}
    
    ; Not getting called when item is sected in DropDownList
    dropDown_SelectionChanged(SelectedIndex)
    {
        MsgBox % SelectedIndex
    }
    

}

Gui_dropDown:
CGUI.HandleEvent()
return


fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Thanks. I'll fix it ASAP.

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
I fixed all bugs you mentioned in the latest commit. I also changed the parameter of SelectionChanged, it is now the SelectedItem instead of the SelectedIndex.

You can add controls to tabs (and other controls containing list-like data like ListViews, TreeViews, ComboBoxes, Check/Radiobuttons) by using the AddControl function. It is normally called on a single list item, such as this.TabControl.Tabs[1].AddControl(). Parameters are the same as CGUI.Add().

Hmm, I'm wondering if I should rename CGUI.Add() to CGUI.AddControl() for better consistency? "Add" is currently also used for adding items to lists.

I think I'll also objectify the menus so that they can have callback functions inside the GUI class.

zzzooo10
  • Members
  • 237 posts
  • Last active: Apr 14 2015 01:57 AM
  • Joined: 19 Dec 2010
I think renaming CGUI.Add() to CGUI.AddControl() would be a great idea, and where can I get the updated version?

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
On GitHub.

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
A structural change:

I found a way that allows skipping the call to Base.__New(). The base constructor is now automatically called when the derived class is instantiated so the user does not have to worry about it.

I also started implementing Menu objects that allow callback functions in the GUI class.

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Menus can now be used with OOP syntax :)
SetBatchlines, -1

MyWindow := new CMyWindow("first") ;Create an instance of this window class

;~ MySecondWindow := new CMyWindow("second") ;Create a second instance of this window class

return



#include <CGUI>

Class CMyWindow Extends CGUI

{

	__New(title)

	{

		this.Title := Title

		this.Resize := true

		this.MinSize := "500x"

		this.CloseOnEscape := true

		this.DestroyOnClose := true

		this.Menu1 := New("CMenu", "Main")

		this.Menu1.AddMenuItem("hello", "test")

		this.Menu1[1].Text := "Test"

		this.Menu1[1].Checked := true

		this.Menu1[1].Enabled := false

		this.Menu1.AddSubMenu("sub1", "Test")

		this.Menu1[2].AddMenuItem("blup", "blup")

		sub2 := New("CMenu", "sub2")

		sub2.AddMenuItem("blah", "blah")

		this.Menu1.AddSubMenu("sub2", sub2)

		sub2.Icon := "C:\Program Files\Autohotkey\SciTE_beta5\AutoHotkey.exe"

		this.Menu1.DeleteMenuItem(1)

		;~ this.Menu(this.Menu1) ;Menu can't be used for context and menu bar at once...

		this.Show("")

		return this

	}

	ContextMenu()

	{

		this.ShowMenu(this.Menu1)

	}

	blup()

	{

		MsgBox blup

	}

	test()

	{

		MsgBox hello

	}

	blah()

	{

		MsgBox blah

	}

	PostDestroy()

	{

		if(!this.Instances.MaxIndex()) ;Exit when all instances of this window are closed

			ExitApp

	}

}