Jump to content

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

Farbige DropDownList


  • Please log in to reply
4 replies to this topic
Dr_Holle
  • Members
  • 105 posts
  • Last active: Mar 26 2014 10:10 AM
  • Joined: 18 Dec 2012

Hallo zusammen...

 

Der User "just me" hat mit Class_CTLCOLORS eine Lösung vorgestellt um Steuerelemente farbig darzustellen.

Leider ist es in Drop-Down-Listen nicht möglich einzelne Zeilen farbig zu markieren.

 

Nun ist es mir gelungen dieses durch den "Hintenrum-Einschleichtrick" zu realisieren. Da das ganze jedoch auf einem Bug (Darstellungs-Aktualisierung) beruht hat das ganze leider 3 Einschränkungen:

 

1. Es ist NICHT möglich die Farbe in einer zugeklappten DropDownList zu sehen. Hier wäre es jedoch möglich in dem Fall (wenn eine farbige Zeile ausgewählt ist) eine ComboBox statt der DropDownList anzuzeigen, da diese farbig dargestellt werden kann.

 

2. Es darf kein Scrollbalken in der DropDownList vorhanden sein, sonst funktioniert das "Bug-using" nicht mehr. Wenn man also sehr große Listen hat wird man mit diesem Script nichts anfangen können, ansonsten kann man z.B. mit "R12" sicherstellen dass alle Monate sichtbar sind und somit kein Scrollbalken vorhanden ist.

 

3. Das "include DDL_Color.ahk" muss NACH dem Gui eingetragen werden, da ich in dem Script auf ein Initialisierungs-Aufruf verzichtet habe und die hwnds sonst noch nicht existieren.

 

 

 

So, nun zum Script (es wird Class_CTLCOLORS von "just me" benötigt) :

 

 

DDL_color.ahk

OnMessage(0x200 , "DDL_refresh")
return

#Include Class_CTLCOLORS.ahk ;from "just me"
#If InStr(DDL_MouseOver("ahk_class") , "ComboBox")
   ~LButton::DDL_initial()
#If   
   ~Up::
   ~Down::
   ~PgUp::
   ~PgDn::
      DDL_refresh()
return

cDDL(hwnd,list,bgcolor = "",fontcolor = "")
{
    global cDDL
    if (!bgcolor && !fontcolor) || !list
    {
        if cDDL[hwnd].list || cDDL[hwnd].bgcolor || cDDL[hwnd].fontcolor
            cDDL.Index -= 1
        cDDL.remove(hwnd)
    }
    else
    {
        if !cDDL.index
        {
            cDDL := Object()
            cDDL.index := 0    
        }
        cDDL[hwnd] := Object("list",list,"bgcolor",bgcolor,"fontcolor",fontcolor) , cDDL.Index += 1
    }
return
}

DDL_MouseOver(WinTitle) {
   MouseGetPos,,,,control
return control
}

DDL_refresh()
{
    global CTLCOLORS , cDDL
   Critical
   DDL_before := DDL
    ControlGetFocus, control, A
   GuiControlGet, DDL,, %control%
    ControlGet, hwnd, Hwnd,, %control%, A
   if (DDL == DDL_before)
      return
   bgcolor := 0
    if DDL in %    cDDL[hwnd].list
      bgColor := 1
   bgColor ? CTLCOLORS.Attach(hwnd, cDDL[hwnd].bgcolor, cDDL[hwnd].fontcolor) : CTLCOLORS.Detach(hwnd)  
Return
}

DDL_initial()
{
    global CTLCOLORS , cDDL
   sleep 5
    Critical
    ControlGetFocus, control, A
   GuiControlGet, DDL,, %control%
    ControlGet, hwnd, Hwnd,, %control%, A    
   SendMessage, 0x157, 0, 0, , ahk_id %hwnd% ;ErrorLevel = 1 --> DDL is open
   if !ErrorLevel
      return   
   ControlGet, DDL_List, List,, %control%, A
   CTLCOLORS.Detach(hwnd)
   Loop, parse, DDL_List,`n,`r
   {
      GuiControl, Choose, %control%, %a_loopfield%
      CTLCOLORS.Attach(hwnd, "", "")
   }
   List := cDDL[hwnd].list
   CTLCOLORS.Detach(hwnd)
   Loop, parse, List, CSV
   {
      GuiControl, Choose, %control%, %a_loopfield%
      CTLCOLORS.Attach(hwnd, cDDL[hwnd].bgcolor, cDDL[hwnd].fontcolor)
   }
   GuiControl, Choose, %Control%, %DDL%
   bgcolor := 0
   if DDL in %List%
      bgColor := 1
   bgColor ? CTLCOLORS.Attach(hwnd, cDDL[hwnd].list, cDDL[hwnd].fontcolor) : CTLCOLORS.Detach(hwnd)    
return
}

Und hier ist ein Beispiel-Script:

Gui, Add, DropDownList, x10 y20 w200 r10 choose3 vLetters hwndhLetters , A|B|C|D|E|F|G|H|I|J
abc = A,B,E,F,I,J
cDDL(hLetters,abc,"Red","White")
Gui, Add, DropDownList, xp y+20 w200 r10 choose2 vDays hwndhDays , Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday
Days = Tuesday,Wednesday,Thursday
cDDL(hDays,Days,"00FFFF","black")
Gui, Add, DropDownList, xp y+20 w200 r12 choose1 vMonths hwndhMonths , January|February|March|April|May|June|July|August|September|October|November|December
Months = January,February,April,October,December
cDDL(hMonths,Months,"blue","00FFFF")
Gui, Show, y50, Test

#include DDL_color.ahk

return

GuiClose:
GuiEscape:
   Gui, Destroy
   CTLCOLORS.Free()
ExitApp

Das ganze ist sicher nicht perfekt, aber (je nach Anwendung) brauchbar.

Verbeserungsvorschläge sind gerne gesehen (konstruktive Kritik auch).

 

Gruß, Holle



Dr_Holle
  • Members
  • 105 posts
  • Last active: Mar 26 2014 10:10 AM
  • Joined: 18 Dec 2012

Hallo,

 

inzwischen habe ich das Script etwas erweitert, und zwar arbeite ich gerade daran dass die farbige Darstellung nun auch bei geschlossenen DropDownLists sichtbar sind. Dieses versuche ich so zu lösen, indem die DDL durch eine ComboBox ersetzt wird, wenn diese geschlossen ist und die aktuelle Auswahl farbig sein soll.

 

Das funktioniert soweit schon ganz gut, aber ich habe da noch ein Problem, und zwar:

 

Wenn ich in der DDL eine Auswahl tätige, welche farbig sein soll wird diese DDL versteckt und an dessen Stelle eine ComboBox plaziert, mit der gleichen Auswahl (und die kann dann ja farbig dargestellt werden). Soweit funktioniert das auch schon.

Wenn ich nun aber die ComboBox öffne soll diese wieder zu einer DDL werden und genau hier ist mein Problem. Das Script versteckt nun also die ComboBox und macht die DDL wieder sichtbar, aber die Anzahl der Reihen ist verloren gegangen.

Ich finde nicht den Grund, warum diese verloren gehen, vielleicht hat hier ja jemand einen Tipp für mich :-)

 

Edit:

Inzwischen habe ich herausgefunden, dass nicht die Anzahl der Zeilen verloren geht, sondern die Funktion wurd mehrfach aufgerufen (ruft sich selber nochmal auf).

Nun habe ich mal ein "Sleep, 1000" verwendet, nun sieht man dass das Script erst genau das macht was es soll, und nach einer Sekunde wird die Funktion dann nochmal aufgerufen (mehrmals sogar, das erkennt man am ToolTip).

Vielleicht hat ja jemand eine Idee wie ich das am geschicktesten Lösen kann. Danke!

 

 

Hier ist das Script (Class_CTLCOLORS.ahk von "just me" wird benötigt, Link siehe im vorherigen Beitrag):

Gui, 4:Add, DropDownList, x10 y20 w200 r10 choose3 vLetters hwndhLetters , A|B|C|D|E|F|G|H|I|J
abc = A,B,E,F,I,J
cDDL(hLetters,abc,"Red","White")
Gui, 4:Add, DropDownList, xp y+20 w200 r10 choose4 vDays hwndhDays , Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday
Days = Tuesday,Wednesday,Thursday
cDDL(hDays,Days,"00FFFF","black")
Gui, 4:Add, DropDownList, xp y+20 w200 r12 choose6 vMonths hwndhMonths , January|February|March|April|May|June|July|August|September|October|November|December
Months = January,February,April,October,December
cDDL(hMonths,Months,"blue","00FFFF")
Gui, 4:Show, y50 , Test

CoordMode, ToolTip

cDDL_initial()

OnMessage(0x200 , "DDL_refresh")
OnMessage(0x111 , "DDL_replace") ;WM_COMMAND = 0x111  ---> Reagiert auf alle möglichen Kommandos

return

#Include Class_CTLCOLORS.ahk ; by "just me"

#If InStr(DDL_MouseOver("ahk_class") , "ComboBox")
    ~LButton::DDL_initial()

cDDL(hwnd,list,bgcolor = "",fontcolor = "")
{
    global cDDL
    if (!bgcolor && !fontcolor) || !list
    {
        if cDDL[hwnd].list || cDDL[hwnd].bgcolor || cDDL[hwnd].fontcolor
            cDDL.Index -= 1
        cDDL.remove(hwnd)
    }
    else
    {
        if !cDDL.index
        {
            cDDL := Object()
            cDDL.index := 0    
        }
        cDDL[hwnd] := Object("list",list,"bgcolor",bgcolor,"fontcolor",fontcolor) , cDDL.Index += 1
    }
return
}

cDDL_initial()
{
    global CTLCOLORS , cDDL , cDDLHwnd := Object()
    WindowHwnd := WinExist("A")    
    Loop
    {
        DDLNumber := "ComboBox" . a_index
        ControlGet, hwnd, Hwnd,, %DDLNumber%, A
        if !hwnd
            break
        gefunden := a_index
    }
    Loop, %gefunden%
    {
        DDLNumber := "ComboBox" . a_index
        ControlGet, hwnd, Hwnd,, %DDLNumber%, A
        GuiControlGet, Pos, %WindowHwnd%:Pos,%hwnd%    
        coords := "x" PosX "y" PosY "w" PosW "h" PosH
        List := cDDL[hwnd].list  
        if List ; Wenn für diese DDL eine Liste existiert, dann dafür auch eine CB anlegen
        {
            ControlGet, auswahl , choice,, %DDLNumber%, A
            ControlGet, ListCB, List,, %DDLNumber%, A ; Inhalt der Liste auslesen
            StringReplace, ListCB, ListCB, `n , | , all ; den Inhalt formatieren
            StringReplace, ListCB, ListCB, %auswahl% , % auswahl . "|" ; die letzte Auswahl vorwählen
            cDDLHwnd[coords,"ddlhwnd"] := hwnd
            Gui, %WindowHwnd%:Add, ComboBox, x%PosX% y%PosY% w%PosW% h%PosH% hwndhCB%hwnd% ReadOnly hidden, %ListCB%
            cDDLHwnd[coords,"cbhwnd"] := hCB%hwnd%
            If auswahl in %List%
            {
                GuiControl, %WindowHwnd%:Hide, % cDDLHwnd[coords,"ddlhwnd"]
                GuiControl, %WindowHwnd%:Show, % cDDLHwnd[coords,"cbhwnd"]
                ddlhwnd := cDDLHwnd[coords,"ddlhwnd"]
                cbhwnd := cDDLHwnd[coords,"cbhwnd"]
                CTLCOLORS.Attach(cbhwnd, cDDL[ddlhwnd].bgcolor, cDDL[ddlhwnd].fontcolor)
            }
        }
    }
return    
}

DDL_Replace(LParam,WParam)
{
    SetFormat, IntegerFast, hex
    LParamHex := LParam .= "" , WParamHex := WParam .= ""
    StringMid, CB_Action, LParam, 3, 1 ; Liest das erste Zeichen aus, welches die Aktion anzeigt (1= Auswahl , 5= Eingabe , 7= Geöffnet , 8= Geschlossen)
    SetFormat, IntegerFast, d
    LParam += 0 ; Macht aus LParam wieder eine Dezimal-Zahl
    WParam += 0 ; Macht aus LParam wieder eine Dezimal-Zahl
ToolTip, Aktion = %cb_action%`nLParam = %LParam% (%LParamHex%)`nWParam=%WParam% (%WParamHex%),800,500,6
;~ sleep 1000
    if CB_Action not in 1,5,6,7,8 ; Lediglich Änderungen der Auswahl und Öffnen/Schließen der DDL/CB soll bearbeitet werden...
        return
    global CTLCOLORS , cDDL , cDDLHwnd
    WindowHwnd := WinExist("A")    
    ControlGetFocus, control, A
    ControlGet, hwnd, Hwnd,, %control%, A
    GuiControlGet, Pos, %WindowHwnd%:Pos,%hwnd%    
    coords := "x" PosX "y" PosY "w" PosW "h" PosH
    if control contains ComboBox  ; Es handelt sich um eine DDL
        cDDLHwnd[coords,"ddlhwnd"] := hwnd
    else if control contains Edit ; Es handelt sich um eine CB
        cDDLHwnd[coords,"cbhwnd"] := hwnd
    GuiControlGet, auswahl , , %hwnd%    ; Auswahl des aktuellen Steuerelements
    if (CB_Action = 7) ; Wenn die DDL oder ComboBox "aufgeklappt" wurde...
    {
        if control contains ComboBox
            DDL_initial()
        else if control contains Edit ; CB muß zur DDL werden
        {
            ToolTip, CB wurde geöffnet,150,1
            ; zur DDL wechseln
            cbhwnd := cDDLHwnd[coords,"cbhwnd"]
            Control, HideDropDown, , , ahk_id %cbhwnd%
            GuiControl, %WindowHwnd%:Hide, % cDDLHwnd[coords,"cbhwnd"]
            GuiControl, %WindowHwnd%:Show, % cDDLHwnd[coords,"ddlhwnd"]
            GuiControl, %WindowHwnd%:Focus, % cDDLHwnd[coords,"ddlhwnd"]
            ddlhwnd := cDDLHwnd[coords,"ddlhwnd"]
            Control, ShowDropDown, , , ahk_id %ddlhwnd%
            GuiControl, %WindowHwnd%:Choose, % cDDLHwnd[coords,"ddlhwnd"] , %auswahl%  
            DDL_initial()
sleep 1000
        }
    return  
    }
    ; Wenn die DDL bereits offen ist, dann abbrechen...
    SendMessage, 0x157, 0, 0, , ahk_id %hwnd% ;ErrorLevel = 1 --> DDL is open
    if ErrorLevel
        return    
    ddlHwnd := cDDLHwnd[coords,"ddlhwnd"]
    List := cDDL[ddlHwnd].list
    if control contains ComboBox ; Control ist eine DDL
    {
        cDDLHwnd[coords,"ddlhwnd"] := hwnd
        if List contains %auswahl%
        { ; Wenn die aktuelle Auswahl auf der Liste steht muss das Steuerelement in eine ComboBox geändert werden.
            ControlGet, ListCB, List,, %control%, A ; Inhalt der Liste auslesen
            StringReplace, ListCB, ListCB, `n , | , all ; den Inhalt formatieren
            StringReplace, ListCB, ListCB, %auswahl% , % auswahl . "|" ; die letzte Auswahl vorwählen
            GuiControl, %WindowHwnd%:Hide, % cDDLHwnd[coords,"ddlhwnd"] ; DDL verstecken
            GuiControl, %WindowHwnd%:Show, % cDDLHwnd[coords,"cbhwnd"]  ; Combobox anzeigen
            GuiControlGet, auswahl , , % cDDLHwnd[coords,"ddlhwnd"]
            GuiControl, %WindowHwnd%:Focus, % cDDLHwnd[coords,"cbhwnd"]  ; Fokus auf die gerade geänderte DDL (nun Combobox) setzen.
            GuiControl, %WindowHwnd%:Choose, % cDDLHwnd[coords,"cbhwnd"], %auswahl%
            ddlhwnd := cDDLHwnd[coords,"ddlhwnd"]
            cbhwnd := cDDLHwnd[coords,"cbhwnd"]
            CTLCOLORS.Attach(cbhwnd, cDDL[ddlhwnd].bgcolor, cDDL[ddlhwnd].fontcolor)          
        }
    }
    else if control contains Edit ; Control ist eine ComboBox
    {
        if List not contains %auswahl%
        { ; Wenn die aktuelle Auswahl NICHT auf der Liste steht muss das Steuerelement in eine DDL geändert werden.
            GuiControl, %WindowHwnd%:Hide, % cDDLHwnd[coords,"cbhwnd"]
            GuiControl, %WindowHwnd%:Show, % cDDLHwnd[coords,"ddlhwnd"]
            GuiControl, %WindowHwnd%:Focus, % cDDLHwnd[coords,"ddlhwnd"]
            GuiControl, %WindowHwnd%:Choose, % cDDLHwnd[coords,"ddlhwnd"] , %auswahl%
        }
    }
return    
}

DDL_MouseOver(WinTitle) {
    MouseGetPos,,,,control
return control
}

DDL_refresh()
{
    global CTLCOLORS , cDDL
    Critical
    DDL_before := DDL
    ControlGetFocus, control, A
    ControlGet, DDL,choice,, %control%, A
    ControlGet, hwnd, Hwnd,, %control%, A
    if (DDL == DDL_before)
    return
    bgcolor := 0
    if DDL in %    cDDL[hwnd].list
    bgColor := 1
    bgColor ? CTLCOLORS.Attach(hwnd, cDDL[hwnd].bgcolor, cDDL[hwnd].fontcolor) : CTLCOLORS.Detach(hwnd)  
Return
}

DDL_initial()
{
    global CTLCOLORS , cDDL
    sleep 5
    Critical
    ControlGetFocus, control, A
    ControlGet, DDL, choice,, %control%, A
    ControlGet, hwnd, Hwnd,, %control%, A
    SendMessage, 0x157, 0, 0, , ahk_id %hwnd% ;ErrorLevel = 1 --> DDL is open
    if !ErrorLevel
        return
    ControlGet, DDL_List, List,, %control%, A
    CTLCOLORS.Detach(hwnd)
    WindowHwnd := WinExist("A")    
    Loop, parse, DDL_List,`n,`r
    {
        GuiControl, %WindowHwnd%:Choose, %control%, %a_loopfield%
        CTLCOLORS.Attach(hwnd, "", "")
    }
    List := cDDL[hwnd].list
    CTLCOLORS.Detach(hwnd)
    Loop, parse, List, CSV
    {
        GuiControl, %WindowHwnd%:Choose, %control%, %a_loopfield%
        CTLCOLORS.Attach(hwnd, cDDL[hwnd].bgcolor, cDDL[hwnd].fontcolor)
    }
    GuiControl, %WindowHwnd%:Choose, %Control%, %DDL%
    bgcolor := 0
    if DDL in %List%
        bgColor := 1
    bgColor ? CTLCOLORS.Attach(hwnd, cDDL[hwnd].list, cDDL[hwnd].fontcolor) : CTLCOLORS.Detach(hwnd)    
return
}

4GuiClose:
    CTLCOLORS.Free()
ExitApp


just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011

Na dann!
 
So ganz erschließen sich mir die Teile Deines Skripts noch nicht, aber einige Ideen habe ich schon.
 
Meiner Meinung nach sollte es reichen, auf maximal drei Nachrichten zu reagieren:

  • CBN_DROPDOWN - Hier muss dafür gesorgt werden, dass auf die DropDownList zurückgeschaltet wird, wenn eine ComboBox aktiv ist.
  • CBN_EDITCHANGE - nicht unbedingt, man könnte hier aber gegen die Auswahlliste prüfen. Der Absender ist immer eine ComboBox!!!
  • CBN_SELCHANGE - Hier muss die neue Auswahl gegen die Auswahlliste geprüft und ggf. auf die ComboBox umgestellt werden.

 

Bevor Du zwischen ComboBox und DropDownList umschaltest, solltest Du den Messagehandler ab- (OnMessage(0x111, "")) und erst danach wieder anschalten (OnMessage(0x111 , "DDL_replace")).
 

    SetFormat, IntegerFast, hex
    LParamHex := LParam .= "" , WParamHex := WParam .= ""
    StringMid, CB_Action, LParam, 3, 1 ; Liest das erste Zeichen aus, welches die Aktion anzeigt (1= Auswahl , 5= Eingabe , 7= Geöffnet , 8= Geschlossen)
    SetFormat, IntegerFast, d

Diese Idee ist mir noch nie gekommen. Normalerweise holt man sich den Nachrichtencode mit nCode := LParam >> 16 (ganz vorsichtige Naturen nehmen nCode := (LParam >> 16) & 0xFFFF).

 

 

Edit: Noch etwas!

 

Im Messagehandler wird Dir in der Variablen A_Gui der Name / die Nummer des GUI übergeben. Damit lässt sich z.B. Folgendes machen:

    GuiControlGet, ClassNN, %A_Gui%:Focus
    GuiControlGet, HCTL, %A_Gui%:HWND, %ClassNN%
    WinGetClass, ClassName, ahk_id %HCTL%
    WinGet, Styles, Style, ahk_id %HCTL%
    If (ClassName = "ComboBox") && ((Styles & 0x03) = 0x03) ; CBS_DROPDOWNLIST := 0x0003
       MsgBox, Bingo! Wir haben eine DropDownList!

Prefer ahkscript.org for the time being.


Dr_Holle
  • Members
  • 105 posts
  • Last active: Mar 26 2014 10:10 AM
  • Joined: 18 Dec 2012

Super vielen Dank, das gibt mir wieder neue Inspiration :-)



Dr_Holle
  • Members
  • 105 posts
  • Last active: Mar 26 2014 10:10 AM
  • Joined: 18 Dec 2012

Meiner Meinung nach sollte es reichen, auf maximal drei Nachrichten zu reagieren:

  • CBN_DROPDOWN - Hier muss dafür gesorgt werden, dass auf die DropDownList zurückgeschaltet wird, wenn eine ComboBox aktiv ist.
  • CBN_EDITCHANGE - nicht unbedingt, man könnte hier aber gegen die Auswahlliste prüfen. Der Absender ist immer eine ComboBox!!!
  • CBN_SELCHANGE - Hier muss die neue Auswahl gegen die Auswahlliste geprüft und ggf. auf die ComboBox umgestellt werden.

OK, habe ich nun geändert
 

Bevor Du zwischen ComboBox und DropDownList umschaltest, solltest Du den Messagehandler ab- (OnMessage(0x111, "")) und erst danach wieder anschalten (OnMessage(0x111 , "DDL_replace")).

Irgendwie klappt das nicht. Entweder wird das in Funktionen nicht unterstützt, oder ich mache irgend etwas anderes falsch. Siehe im Script weiter unten...
 

    SetFormat, IntegerFast, hex
    LParamHex := LParam .= "" , WParamHex := WParam .= ""
    StringMid, CB_Action, LParam, 3, 1 ; Liest das erste Zeichen aus, welches die Aktion anzeigt (1= Auswahl , 5= Eingabe , 7= Geöffnet , 8= Geschlossen)
    SetFormat, IntegerFast, d
Diese Idee ist mir noch nie gekommen. Normalerweise holt man sich den Nachrichtencode mit nCode := LParam >> 16 (ganz vorsichtige Naturen nehmen nCode := (LParam >> 16) & 0xFFFF).

 

Oh, vielen Dank. Das ist viel besser, habe ich nun auch direkt geändert.
 
 

Im Messagehandler wird Dir in der Variablen A_Gui der Name / die Nummer des GUI übergeben. Damit lässt sich z.B. Folgendes machen:

    GuiControlGet, ClassNN, %A_Gui%:Focus
    GuiControlGet, HCTL, %A_Gui%:HWND, %ClassNN%
    WinGetClass, ClassName, ahk_id %HCTL%
    WinGet, Styles, Style, ahk_id %HCTL%
    If (ClassName = "ComboBox") && ((Styles & 0x03) = 0x03) ; CBS_DROPDOWNLIST := 0x0003
       MsgBox, Bingo! Wir haben eine DropDownList!

Ich weiß nicht mehr genau warum, aber ursprünglich hatte ich auch die A_Gui für sowas benutzt, aber dann bliebt die manchmal leer (in einem anderen Script) und seitdem nutze ich immer die andere Methode. In diesem Script wird das aber wahrscheinlich mit A_Gui keine Probleme geben, deswegen werde ich das später noch ändern.
Was muss ich denn machen damit ich eine ComboBox erkenne?

 

Edit: Habe es nun doch selber hinbekommen dass es auch bei der ComboBox klappt, und zwar habe ich das bereits vorher ermittelte hwnd benutzt, so geht es nun (siehe im Script weiter unten). Mit den Code-Zeilen im Zitat blieb Styles leer, wenn eine ComboBox geöffnet wurde, bei der DDL hingegen klappte das wunderbar.


Hier ist das aktuelle (noch fehlerhafte!) Script :

Gui, 4:Add, DropDownList, x10 y20 w200 r10 choose3 vLetters hwndhLetters , A|B|C|D|E|F|G|H|I|J
abc = A,B,E,F,I,J
cDDL(hLetters,abc,"Red","White")
Gui, 4:Add, DropDownList, xp y+20 w200 r10 choose4 vDays hwndhDays , Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday
Days = Tuesday,Wednesday,Thursday
cDDL(hDays,Days,"00FFFF","black")
Gui, 4:Add, DropDownList, xp y+20 w200 r12 choose6 vMonths hwndhMonths , January|February|March|April|May|June|July|August|September|October|November|December
Months = January,February,April,October,December
cDDL(hMonths,Months,"blue","00FFFF")
Gui, 4:Show, y50 , Test

CoordMode, ToolTip

cDDL_initial()

OnMessage(0x200 , "DDL_refresh")
OnMessage(0x111 , "DDL_replace") ;WM_COMMAND = 0x111  ---> Reagiert auf alle möglichen Kommandos

return

#Include Class_CTLCOLORS.ahk ; by "just me"

#If InStr(DDL_MouseOver("ahk_class") , "ComboBox")
    ~LButton::DDL_initial()

cDDL(hwnd,list,bgcolor = "",fontcolor = "")
{
    global cDDL
    if (!bgcolor && !fontcolor) || !list
    {
        if cDDL[hwnd].list || cDDL[hwnd].bgcolor || cDDL[hwnd].fontcolor
            cDDL.Index -= 1
        cDDL.remove(hwnd)
    }
    else
    {
        if !cDDL.index
        {
            cDDL := Object()
            cDDL.index := 0    
        }
        cDDL[hwnd] := Object("list",list,"bgcolor",bgcolor,"fontcolor",fontcolor) , cDDL.Index += 1
    }
return
}

cDDL_initial()
{
    global CTLCOLORS , cDDL , cDDLHwnd := Object()
    WindowHwnd := WinExist("A")    
    Loop
    {
        DDLNumber := "ComboBox" . a_index
        ControlGet, hwnd, Hwnd,, %DDLNumber%, A
        if !hwnd
            break
        gefunden := a_index
    }
    Loop, %gefunden%
    {
        DDLNumber := "ComboBox" . a_index
        ControlGet, hwnd, Hwnd,, %DDLNumber%, A
        GuiControlGet, Pos, %WindowHwnd%:Pos,%hwnd%    
        coords := "x" PosX "y" PosY "w" PosW "h" PosH
        List := cDDL[hwnd].list  
        if List ; Wenn für diese DDL eine Liste existiert, dann dafür auch eine CB anlegen
        {
            ControlGet, auswahl , choice,, %DDLNumber%, A
            ControlGet, ListCB, List,, %DDLNumber%, A ; Inhalt der Liste auslesen
            StringReplace, ListCB, ListCB, `n , | , all ; den Inhalt formatieren
            StringReplace, ListCB, ListCB, %auswahl% , % auswahl . "|" ; die letzte Auswahl vorwählen
            cDDLHwnd[coords,"ddlhwnd"] := hwnd
            Gui, %WindowHwnd%:Add, ComboBox, x%PosX% y%PosY% w%PosW% h%PosH% hwndhCB%hwnd% ReadOnly hidden, %ListCB%
            cDDLHwnd[coords,"cbhwnd"] := hCB%hwnd%
            If auswahl in %List%
            {
                GuiControl, %WindowHwnd%:Hide, % cDDLHwnd[coords,"ddlhwnd"]
                GuiControl, %WindowHwnd%:Show, % cDDLHwnd[coords,"cbhwnd"]
                ddlhwnd := cDDLHwnd[coords,"ddlhwnd"]
                cbhwnd := cDDLHwnd[coords,"cbhwnd"]
                CTLCOLORS.Attach(cbhwnd, cDDL[ddlhwnd].bgcolor, cDDL[ddlhwnd].fontcolor)
            }
        }
    }
return    
}

DDL_Replace(LParam,WParam)
{
ToolTip   
    OnMessage(0x111, "")
    nCode := ((LParam >> 16) & 0xFFFF)    

    if nCode not in 1,5,7 ; Lediglich Änderungen der Auswahl und Öffnen/Schließen der DDL/CB soll bearbeitet werden...
    {
        OnMessage(0x111 , "DDL_replace")
        return
    }
MsgBox nCode=%nCode%   
    global CTLCOLORS , cDDL , cDDLHwnd
    ControlGetFocus, control, A
    ControlGet, hwnd, Hwnd,, %control%, A
    GuiControlGet, Pos, %A_Gui%:Pos,%hwnd%    
    coords := "x" PosX "y" PosY "w" PosW "h" PosH
    GuiControlGet, auswahl , , %hwnd%    ; Auswahl des aktuellen Steuerelements
    WinGetClass, ClassName, ahk_id %hwnd%
    WinGet, Styles, Style, ahk_id %hwnd%    
    If (ClassName = "ComboBox") && ((Styles & 0x03) = 0x03) ; CBS_DROPDOWNLIST := 0x0003
        ;~ TrayTip,, Ich bin eine DropDownList!`n`nStyles = %Styles%`nClassName=%ClassName%`nGui=%A_gui%`nControl=%control%
        cDDLHwnd[coords,"ddlhwnd"] := hwnd
    else If (ClassName = "Edit") && (!(Styles & 0x03)) ; CBS_DROPDOWNLIST := 0x0003
        ;~ TrayTip,, Nun bin ich eine ComboBox!`n`nStyles = %Styles%`nClassName=%ClassName%`nGui=%A_gui%`nControl=%control%
        cDDLHwnd[coords,"cbhwnd"] := hwnd
    if (nCode = 7) ; Wenn die DDL oder ComboBox "aufgeklappt" wurde...
    {
        if control contains ComboBox
        {
            ToolTip, DDL wurde geöffnet,150,1
            DDL_initial()
        }
        else if control contains Edit ; CB muß zur DDL werden
        {
            ToolTip, CB wurde geöffnet,150,1
            ; zur DDL wechseln
            cbhwnd := cDDLHwnd[coords,"cbhwnd"]
            Control, HideDropDown, , , ahk_id %cbhwnd%
            GuiControl, %A_Gui%:Hide, % cDDLHwnd[coords,"cbhwnd"]
            GuiControl, %A_Gui%:Show, % cDDLHwnd[coords,"ddlhwnd"]
            GuiControl, %A_Gui%:Focus, % cDDLHwnd[coords,"ddlhwnd"]
            ddlhwnd := cDDLHwnd[coords,"ddlhwnd"]
            Control, ShowDropDown, , , ahk_id %ddlhwnd%
            GuiControl, %A_Gui%:Choose, % cDDLHwnd[coords,"ddlhwnd"] , %auswahl%        
            DDL_initial()
TrayTip,, Bis hier scheint alles zu passen...
pause
        }
        OnMessage(0x111 , "DDL_replace")

    return  
    }
    ; Wenn die DDL bereits offen ist, dann abbrechen...
    SendMessage, 0x157, 0, 0, , ahk_id %hwnd% ;ErrorLevel = 1 --> DDL is open
    if ErrorLevel
    {
        OnMessage(0x111 , "DDL_replace")
        return    
    }
    ddlHwnd := cDDLHwnd[coords,"ddlhwnd"]
    List := cDDL[ddlHwnd].list
    if control contains ComboBox ; Control ist eine DDL
    {
        cDDLHwnd[coords,"ddlhwnd"] := hwnd
        if List contains %auswahl%
        { ; Wenn die aktuelle Auswahl auf der Liste steht muss das Steuerelement in eine ComboBox geändert werden.
            ControlGet, ListCB, List,, %control%, A ; Inhalt der Liste auslesen
            StringReplace, ListCB, ListCB, `n , | , all ; den Inhalt formatieren
            StringReplace, ListCB, ListCB, %auswahl% , % auswahl . "|" ; die letzte Auswahl vorwählen
            GuiControl, %A_Gui%:Hide, % cDDLHwnd[coords,"ddlhwnd"] ; DDL verstecken
            GuiControl, %A_Gui%:Show, % cDDLHwnd[coords,"cbhwnd"]  ; Combobox anzeigen
            GuiControlGet, auswahl , , % cDDLHwnd[coords,"ddlhwnd"]
            GuiControl, %A_Gui%:Focus, % cDDLHwnd[coords,"cbhwnd"]  ; Fokus auf die gerade geänderte DDL (nun Combobox) setzen.
            GuiControl, %A_Gui%:Choose, % cDDLHwnd[coords,"cbhwnd"], %auswahl%
            ddlhwnd := cDDLHwnd[coords,"ddlhwnd"]
            cbhwnd := cDDLHwnd[coords,"cbhwnd"]
            CTLCOLORS.Attach(cbhwnd, cDDL[ddlhwnd].bgcolor, cDDL[ddlhwnd].fontcolor)          
        }
    }
    else if control contains Edit ; Control ist eine ComboBox
    {
        if List not contains %auswahl%
        { ; Wenn die aktuelle Auswahl NICHT auf der Liste steht muss das Steuerelement in eine DDL geändert werden.
            GuiControl, %A_Gui%:Hide, % cDDLHwnd[coords,"cbhwnd"]
            GuiControl, %A_Gui%:Show, % cDDLHwnd[coords,"ddlhwnd"]
            GuiControl, %A_Gui%:Focus, % cDDLHwnd[coords,"ddlhwnd"]
            GuiControl, %A_Gui%:Choose, % cDDLHwnd[coords,"ddlhwnd"] , %auswahl%
        }
    }
    OnMessage(0x111 , "DDL_replace")
return    
}

DDL_MouseOver(WinTitle) {
    MouseGetPos,,,,control
return control
}

DDL_refresh()
{
    global CTLCOLORS , cDDL
    Critical
    DDL_before := DDL
    ControlGetFocus, control, A
    ControlGet, DDL,choice,, %control%, A
    ControlGet, hwnd, Hwnd,, %control%, A
    if (DDL == DDL_before)
    return
    bgcolor := 0
    if DDL in %    cDDL[hwnd].list
    bgColor := 1
    bgColor ? CTLCOLORS.Attach(hwnd, cDDL[hwnd].bgcolor, cDDL[hwnd].fontcolor) : CTLCOLORS.Detach(hwnd)  
Return
}

DDL_initial()
{
    global CTLCOLORS , cDDL
    sleep 5
    Critical
    ControlGetFocus, control, A
    ControlGet, DDL, choice,, %control%, A
    ControlGet, hwnd, Hwnd,, %control%, A
    SendMessage, 0x157, 0, 0, , ahk_id %hwnd% ;ErrorLevel = 1 --> DDL is open
    if !ErrorLevel
        return
    ControlGet, DDL_List, List,, %control%, A
    CTLCOLORS.Detach(hwnd)
    WindowHwnd := WinExist("A")    
    Loop, parse, DDL_List,`n,`r
    {
        GuiControl, %WindowHwnd%:Choose, %control%, %a_loopfield%
        CTLCOLORS.Attach(hwnd, "", "")
    }
    List := cDDL[hwnd].list
    CTLCOLORS.Detach(hwnd)
    Loop, parse, List, CSV
    {
        GuiControl, %WindowHwnd%:Choose, %control%, %a_loopfield%
        CTLCOLORS.Attach(hwnd, cDDL[hwnd].bgcolor, cDDL[hwnd].fontcolor)
    }
    GuiControl, %WindowHwnd%:Choose, %Control%, %DDL%
    bgcolor := 0
    if DDL in %List%
        bgColor := 1
    bgColor ? CTLCOLORS.Attach(hwnd, cDDL[hwnd].list, cDDL[hwnd].fontcolor) : CTLCOLORS.Detach(hwnd)    
return
}

4GuiClose:
    CTLCOLORS.Free()
ExitApp

Wenn das nun mit dem Ausschalten der OnMessage klappen würde wäre das Script schon fast fertig.

 

Edit: Das mit den OnMessage funktioniert doch, aber nach dem erneuten aktivieren wird die Funktion nochmal aufgerufen.

 

Noch mal Edit: Mithilfe der "Pause"-Funktion kann man sehen dass das Script nun eigentlich soweit funktioniert, wenn da nicht noch ein weiterer Aufruf folgen würde.