2012-02-06 31 views
5

साधारण विंडोज कॉम्बोबॉक्स (csDropDown या csDropDownList शैली) कॉम्बो के ऊपर, नीचे कोई स्थान नहीं छोड़ा गया है, या नीचे अपनी ड्रॉपडाउन सूची खुल जाएगा। क्या मैं इस सूची की स्थिति को नियंत्रित कर सकता हूं (कम से कम वाई समन्वय द्वारा)?क्या मैं प्रोग्रामेटिक रूप से कॉम्बोबॉक्स ड्रॉपडाउन सूची की स्थिति निर्धारित कर सकता हूं?

+6

बस सोच रहा है: क्यों? डिफ़ॉल्ट व्यवहार में आपकी पसंद के अनुसार क्या नहीं है? –

+0

@ मारजन वेनेमा हमारे डिजाइनर डी -5 के साथ XP में परीक्षण किए गए मालिक-ड्रा combobox – Andrew

उत्तर

10

एक कोड उदाहरण है कि ड्रॉप-डाउन सूची एनीमेशन सही ढंग से दिखाई देगा और ComboBox1 ऊपर ड्रॉप-डाउन सूची दिखा बाध्य करेगा पोस्ट करना।

TForm1 = class(TForm) 
    ComboBox1: TComboBox; 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
private 
    FComboBoxListDropDown: Boolean; 
    FComboBoxListWnd: HWND; 
    FOldComboBoxListWndProc, FNewComboBoxListWndProc: Pointer; 
    procedure ComboBoxListWndProc(var Message: TMessage); 
end; 

.... 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    Info: TComboBoxInfo; 
begin 
    ZeroMemory(@Info, SizeOf(Info)); 
    Info.cbSize := SizeOf(Info); 
    GetComboBoxInfo(ComboBox1.Handle, Info); 
    FComboBoxListWnd := Info.hwndList; 
    FNewComboBoxListWndProc := MakeObjectInstance(ComboBoxListWndProc); 
    FOldComboBoxListWndProc := Pointer(GetWindowLong(FComboBoxListWnd, GWL_WNDPROC)); 
    SetWindowLong(FComboBoxListWnd, GWL_WNDPROC, Integer(FNewComboBoxListWndProc)); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    SetWindowLong(FComboBoxListWnd, GWL_WNDPROC, Integer(FOldComboBoxListWndProc)); 
    FreeObjectInstance(FNewComboBoxListWndProc); 
end; 

procedure TForm1.ComboBoxListWndProc(var Message: TMessage); 
var 
    R: TRect; 
    DY: Integer; 
begin 
    if (Message.Msg = WM_MOVE) and not FComboBoxListDropDown then 
    begin 
    FComboBoxListDropDown := True; 
    try 
     GetWindowRect(FComboBoxListWnd, R); 
     DY := (R.Bottom - R.Top) + ComboBox1.Height + 1; 
     // set new Y position for drop-down list: always above ComboBox1 
     SetWindowPos(FComboBoxListWnd, 0, R.Left, R.Top - DY , 0, 0, 
     SWP_NOOWNERZORDER or SWP_NOZORDER or SWP_NOSIZE or SWP_NOSENDCHANGING); 
    finally 
     FComboBoxListDropDown := False; 
    end; 
    end; 
    Message.Result := CallWindowProc(FOldComboBoxListWndProc, 
    FComboBoxListWnd, Message.Msg, Message.WParam, Message.LParam); 
end; 

नोट: इस कोड ComboBox hwndList उपवर्गों

  1. मैं पूरी तरह दाऊद से सहमत हैं, और दूसरों है कि यह एक बुरा विचार TComboBox के लिए इस विशिष्ट डिफ़ॉल्ट व्यवहार को बदलने के लिए है। ओपी ने अभी तक का जवाब नहीं दिया है क्यों वह ऐसा व्यवहार चाहता था।
  2. उपरोक्त कोड का परीक्षण डी 5/एक्सपी के साथ किया गया था।
+0

पर सफलतापूर्वक परीक्षण किया है, धन्यवाद! – Andrew

4

ठीक है, आप सूची के लिए उपयोग की गई विंडो में हैंडल प्राप्त करने के लिए GetComboBoxInfo का उपयोग कर ऐसा कर सकते हैं, और फिर उस विंडो को ले जाएं। इस तरह:

type 
    TMyForm = class(TForm) 
    ComboBox1: TComboBox; 
    procedure ComboBox1DropDown(Sender: TObject); 
    protected 
    procedure WMMoveListWindow(var Message: TMessage); message WM_MOVELISTWINDOW; 
    end; 

.... 

procedure TMyForm.ComboBox1DropDown(Sender: TObject); 
begin 
    PostMessage(Handle, WM_MOVELISTWINDOW, 0, 0); 
end; 

procedure TMyForm.WMMoveListWindow(var Message: TMessage); 
var 
    cbi: TComboBoxInfo; 
    Rect: TRect; 
    NewTop: Integer; 
begin 
    cbi.cbSize := SizeOf(cbi); 
    GetComboBoxInfo(ComboBox1.Handle, cbi); 
    GetWindowRect(cbi.hwndList, Rect); 
    NewTop := ClientToScreen(Point(0, ComboBox1.Top-Rect.Height)).Y; 
    MoveWindow(cbi.hwndList, Rect.Left, NewTop, Rect.Width, Rect.Height, True); 
end; 

मैंने कोड को सरल रखने के लिए त्रुटि जांच के मुद्दे को अनदेखा कर दिया है।

हालांकि, चेतावनी दी जानी चाहिए कि यह बहुत भयानक लग रहा है क्योंकि ड्रॉपडाउन एनीमेशन अभी भी दिखाया गया है। शायद आप इसे अक्षम करने का एक तरीका ढूंढ सकते हैं।

हालांकि, आपको बस ऐसा कुछ करने की आवश्यकता नहीं है क्योंकि विंडोज़ पहले से ही आपके लिए यह करता है। एक फॉर्म को स्क्रीन के नीचे खींचें और अपना कॉम्बो ड्रॉप करें। फिर आप सूची को कॉम्बो के ऊपर दिखाई देंगे। इस तरह:

enter image description here

+3

के लिए कुछ उपयोगिता सुधार करना चाहते हैं। यह कोड मेरे लिए काम नहीं कर रहा है। 'cbi.hwndList' स्थानांतरित नहीं किया जा रहा है। यह तुरंत खुलता है और बंद हो जाता है। – kobik

+1

@kobik फिर भी ऐसा करने का एक अन्य कारण नहीं है। मुझे उम्मीद है कि यह मुद्दा डी 5 के बजाय एक्सपी के साथ है। आपको शायद विभिन्न ओएस संस्करणों के लिए व्यवहार स्विच करने की आवश्यकता है। कभी अच्छी योजना नहीं है। –

+2

मैं 100% सहमत हूं। यह शायद 'GWL_WNDPROC' को हुक करके और 'WM_SIZE' को संभालने के द्वारा किया जा सकता है, लेकिन व्यवहार इतना अप्रत्याशित है कि मैं इस विचार को पूरी तरह से डंप कर दूंगा। सिर्फ एक तरफ टिप्पणी, मुझे लगता है कि 'GetComboBoxInfo' का उपयोग सीबी_जीईटीसीएमबीओबीएक्सआईएफओओ से बेहतर है (एमएसडीएन पर दुर्घटनाओं के बारे में टिप्पणी देखें)। – kobik