2015-10-08 14 views
16

में रनटाइम डीपीआई परिवर्तन के बाद मेनू स्केलिंग को संभालने के लिए कैसे करें जब रनटाइम डीपीआई स्विचिंग के लिए समर्थन फॉर्म वर्ग में जोड़ा गया था, मेनू जैसे मूल यूआई तत्वों पर कोई विचार नहीं दिया गया था।डेल्फी सिएटल

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

यह मुख्य मेनू बार, इसके पॉपअप मेनू और फ़ॉर्म पर सभी पॉपअप मेनू के लिए एक समस्या है। यदि इनमें से कोई भी सिस्टम मॉनिटर की तुलना में एक अलग डीपीआई के साथ मॉनिटर में स्थानांतरित नहीं किया जाता है तो इनमें से कोई भी स्केल नहीं है।

वास्तव में यह काम करने का एकमात्र तरीका वीसीएल को ठीक करना है। बहु-डीपीआई को निकालने के लिए एम्बरकेडरो की प्रतीक्षा करना वास्तव में एक विकल्प नहीं है।

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

इस सीमा के आसपास काम करने का सही तरीका क्या है, इसमें शामिल वर्गों को पूरी तरह से फिर से लिखने के बिना?

मेरा पहला झुकाव मेन्यू पॉपअप का ट्रैक रखने के लिए एक चक्कर लगाने का उपयोग करना है और स्क्रीन को ओवरराइड करना है। मेन्यूफॉन्ट संपत्ति जब इसे मेनू सेट अप करने के लिए उपयोग किया जा रहा है। ऐसा लगता है कि एक हैक की बहुत अधिक है।

+0

क्या आप वाकई वीसीएल हैं? क्या नोटपैड यह सही है? –

+0

नोटपैड एक उच्च-डीपीआई जागरूक ऐप नहीं है इसलिए मैं इसका परीक्षण नहीं कर सकता। मुझे यकीन है कि यह वीसीएल है क्योंकि यह मेनू के अपने चित्र को संभालने वाला है, और मैंने कुछ कोड को फिर से लिखकर प्रयोग किया। समस्या यह मुश्किल नहीं है, वास्तव में - जब पॉपअपमेनू डिफ़ॉल्ट tmenuitem माप और ड्राइंग के लिए कैनवास सेट करता है, तो यह स्क्रीन को मैन्यूफॉन्ट फ़ॉन्ट को कैनवास में निर्दिष्ट करता है, जो विंडोज़ से (सिस्टम, मेट्रिक्स) वास्तव में सिस्टम मेट्रिक्स का उपयोग कर रहा है मॉनीटर-विशिष्ट मीट्रिक। –

+0

आप देखते हैं कि मुझे नहीं लगता कि यह वीसीएल है क्योंकि यह मेरे डेल्फी ऐप में भी सिस्टम खींचा मेनू के साथ होता है। आप ग्लिफ का उपयोग करके सिस्टम तैयार मेनू को मजबूर कर आसानी से जांच सकते हैं। –

उत्तर

5

यहां एक समाधान है जो अभी के लिए काम कर रहा है। Delphi Detours Library का उपयोग करके, इस इकाई को डीपीआर उपयोग सूची में जोड़ना (मुझे इसे अन्य रूपों से पहले अपनी सूची के शीर्ष पर रखना था) मेनू आइटम को रखने वाले फ़ॉर्म के आधार पर मेनू कैनवास पर सही फ़ॉन्ट आकार लागू किया जाता है किसी भी पॉपअप मेनू में। यह समाधान जानबूझकर अपरिवर्तनीय मेनू (मुख्य मेनू बार) को अनदेखा करता है क्योंकि वीसीएल मालिक के मापे गए आइटमों के साथ ठीक तरह से निपटता नहीं है।

unit slMenuDPIFix; 

// add this unit to the main application dpr file BEFORE ANY FORMS in the uses list. 

interface 

implementation 

uses 
    Winapi.Windows, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Menus, slScaleUtils, Math, 
    DDetours; 

type 
    TMenuClass = class(TMenu); 
    TMenuItemClass = class(TMenuItem); 

var 
    TrampolineMenuCreate: procedure(const Self: TMenuClass; AOwner: TComponent) = nil; 
    TrampolineMenuItemAdvancedDrawItem: procedure(const Self: TMenuItemClass; ACanvas: TCanvas; ARect: TRect; State: TOwnerDrawState; TopLevel: Boolean) = nil; 
    TrampolineMenuItemMeasureItem: procedure(const Self: TMenuItemClass; ACanvas: TCanvas; var Width, Height: Integer) = nil; 

function GetPopupDPI(const MenuItem: TMenuItemClass): Integer; 
var 
    pm: TMenu; 
    pcf: TCustomForm; 
begin 
    Result := Screen.PixelsPerInch; 
    pm := MenuItem.GetParentMenu; 
    if Assigned(pm) and (pm.Owner is TControl) then 
    pcf := GetParentForm(TControl(pm.Owner)) 
    else 
    pcf := nil; 
    if Assigned(pcf) and (pcf is TForm) then 
    Result := TForm(pcf).PixelsPerInch; 
end; 

procedure MenuCreateHooked(const Self: TMenuClass; AOwner: TComponent); 
begin 
    TrampolineMenuCreate(Self, AOwner); 
    Self.OwnerDraw := True;  // force always ownerdraw. 
end; 

procedure MenuItemAdvancedDrawItemHooked(const Self: TMenuItemClass; ACanvas: TCanvas; ARect: TRect; State: TOwnerDrawState; TopLevel: Boolean); 
begin 
    if (not TopLevel) then 
    begin 
    ACanvas.Font.Height := MulDiv(ACanvas.Font.Height, GetPopupDPI(Self), Screen.PixelsPerInch); 
    end; 
    TrampolineMenuItemAdvancedDrawItem(Self, ACanvas, ARect, State, TopLevel); 
end; 

procedure MenuItemMeasureItemHooked(const Self: TMenuItemClass; ACanvas: TCanvas; var Width, Height: Integer); 
var 
    lHeight: Integer; 
    pdpi: Integer; 
begin 
    pdpi := GetPopupDPI(Self); 
    if (Self.Caption <> cLineCaption) and (pdpi <> Screen.PixelsPerInch) then 
    begin 
    ACanvas.Font.Height := MulDiv(ACanvas.Font.Height, pdpi, Screen.PixelsPerInch); 
    lHeight := ACanvas.TextHeight('|') + MulDiv(6, pdpi, Screen.PixelsPerInch); 
    end else 
    lHeight := 0; 

    TrampolineMenuItemMeasureItem(Self, ACanvas, Width, Height); 

    if lHeight > 0 then 
    Height := Max(Height, lHeight); 
end; 

initialization 

    TrampolineMenuCreate := InterceptCreate(@TMenuClass.Create, @MenuCreateHooked); 
    TrampolineMenuItemAdvancedDrawItem := InterceptCreate(@TMenuItemClass.AdvancedDrawItem, @MenuItemAdvancedDrawItemHooked); 
    TrampolineMenuItemMeasureItem := InterceptCreate(@TMenuItemClass.MeasureItem, @MenuItemMeasureItemHooked); 

finalization 

    InterceptRemove(@TrampolineMenuCreate); 
    InterceptRemove(@TrampolineMenuItemAdvancedDrawItem); 
    InterceptRemove(@TrampolineMenuItemMeasureItem); 

end. 

एक बस के रूप में आसानी से Vcl.Menus पैच सकता है, लेकिन मैं ऐसा नहीं करना चाहता था।

+0

सिस्टम खींचे गए मेनू के साथ क्या होता है? क्या वे ठीक से स्केल कर रहे हैं? यदि ऐसा है तो यह कुछ भी करने के लिए मूर्खतापूर्ण होगा लेकिन सिस्टम को काम करने दें। –

+0

नहीं, वे सही ढंग से तैयार नहीं होते हैं। मुझे कारण पता नहीं है; मुझे लगता है कि इसे आधा बेक्ड विंडोज कार्यक्षमता के साथ करना है। "सिस्टम इसे करने दें" मेरी वरीयता होगी लेकिन 1 9 2 डीपीआई मॉनीटर पर एक 96 डीपीआई मेनू अनुपयोगी है। यही कारण है कि मैं स्पष्ट रूप से वहां मालिक को सही करने के लिए सेट कर रहा हूं। –

+0

क्या आप वाकई अपने परीक्षण में सिस्टम तैयार मेनू का उपयोग कर रहे हैं? वीसीएल उपयोग प्रणाली तैयार मेनू बनाने के लिए कोई ग्लिफ होने की आवश्यकता नहीं है। वीसीएल का मेरा संस्करण ग्लिफ के साथ सिस्टम तैयार मेनू कर सकता है, लेकिन एम्बा नहीं कर सकता है। –

संबंधित मुद्दे