जब Windows फ़ॉन्ट स्केलिंग 100% से अधिक हो, तो मैं अपना GUI कैसे व्यवहार कर सकता / सकती हूं


107

जब विंडोज कंट्रोल पैनल (जैसे 125%, या 150%) में बड़े फ़ॉन्ट आकार चुनते हैं, तो एक वीसीएल एप्लिकेशन में समस्याएं होती हैं, हर बार कुछ निर्धारित किया गया है।

ले लो TStatusBar.Panel। मैंने इसकी चौड़ाई निर्धारित की है ताकि इसमें ठीक एक लेबल हो, अब बड़े फोंट के साथ लेबल "ओवरफ्लो" हो। अन्य घटकों के साथ भी यही समस्या है।

डेल जहाज से कुछ नए लैपटॉप पहले से ही डिफ़ॉल्ट सेटिंग के रूप में 125% के साथ हैं, इसलिए अतीत में यह समस्या काफी दुर्लभ थी अब यह वास्तव में महत्वपूर्ण है।

इस समस्या को दूर करने के लिए क्या किया जा सकता है?

जवाबों:


56

नोट: कृपया अन्य उत्तरों को देखें क्योंकि उनमें बहुत मूल्यवान तकनीकें हैं। यहाँ मेरा जवाब केवल डीपीआई-जागरूकता मानने के खिलाफ चेतावनी और चेतावनी प्रदान करता है।

मैं आम तौर पर DPI- सजग स्केलिंग से बचता हूं TForm.Scaled = True। DPI जागरूकता केवल मेरे लिए महत्वपूर्ण है जब यह उन ग्राहकों के लिए महत्वपूर्ण हो जाता है जो मुझे कॉल करते हैं और इसके लिए भुगतान करने के लिए तैयार हैं। उस दृष्टिकोण के पीछे तकनीकी कारण यह है कि डीपीआई-जागरूकता या नहीं, आप चोट की दुनिया में एक खिड़की खोल रहे हैं। कई मानक और तीसरे पक्ष के वीसीएल नियंत्रण उच्च डीपीआई में अच्छी तरह से काम नहीं करते हैं। उल्लेखनीय रूप से अपवाद है कि विंडोज कॉमन कंट्रोल को लपेटने वाले वीसीएल पार्ट्स उच्च डीपीआई में उल्लेखनीय रूप से अच्छी तरह से काम करते हैं। बड़ी संख्या में तीसरे पक्ष और अंतर्निहित डेल्फी वीसीएल कस्टम नियंत्रण उच्च डीपीआई में, या बिल्कुल भी अच्छी तरह से काम नहीं करते हैं। यदि आप TForm को चालू करने की योजना बनाते हैं। सुनिश्चित करें कि आपके प्रोजेक्ट में हर एक फॉर्म के लिए 96, 125 और 150 DPI पर परीक्षण किया जाना सुनिश्चित है, और आपके द्वारा उपयोग किए जाने वाले नियंत्रण में बनाया गया है।

डेल्फी में ही डेल्फी लिखा जाता है। इसमें अधिकांश रूपों के लिए उच्च डीपीआई जागरूकता झंडा है, हालांकि हाल ही में डेल्फी एक्सई 2 के रूप में, आईडीई लेखकों ने खुद को उस उच्च डीपीआई जागरूकता घोषणापत्र को चालू करने का फैसला नहीं किया। ध्यान दें कि डेल्फी एक्सई 4 और बाद में, उच्च डीपीआई जागरूकता झंडा चालू है, और आईडीई अच्छा दिखता है।

मेरा सुझाव है कि आप TForm.Scaled = true का उपयोग न करें (जो डेल्फी में एक डिफ़ॉल्ट है, इसलिए जब तक आपने इसे संशोधित नहीं किया है, आपके अधिकांश रूपों में उच्च DPI अवेयर फ्लैग के साथ स्केल्ड = सत्य है) (जैसा डेविड के उत्तरों में दिखाया गया है) VCL अनुप्रयोग जो अंतर्निहित डेल्फी फॉर्म डिजाइनर का उपयोग करके बनाए जाते हैं।

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

डेल्फी एक्सई ऐसा दिखता है जब आप विंडोज 7 में डीपीआई स्केलिंग को "फ़ॉन्ट्स @ 200%" पर सेट करते हैं, और डेल्फी एक्सई 2 विंडोज 7 और 8 पर समान रूप से टूट जाता है, लेकिन ये ग्लिच डेल्फी एक्सई 4 के रूप में तय किए जाते हैं:

यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें

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

डीपीआई वर्चुअलाइजेशन को केवल तभी बंद करें जब यह दर्द का नया अतिरिक्त स्रोत, और मुश्किल विकल्प चाहता है। मेरा सुझाव है कि आप इसे अकेला छोड़ दें। ध्यान दें कि विंडोज कॉमन कंट्रोल ज्यादातर ठीक काम करते हैं। ध्यान दें कि डेल्फी डेटा-एक्सप्लोरर नियंत्रण एक मानक # विंडोज ट्री कॉमन कंट्रोल के आसपास C # WinForms आवरण है। यह एक शुद्ध microsoft glitch है, और इसे ठीक करने के लिए या तो Embarcadero को अपने डेटा एक्सप्लोरर के लिए एक शुद्ध पूर्व .Net ट्री नियंत्रण को फिर से लिखना होगा, या नियंत्रण में आइटम हाइट्स को बदलने के लिए कुछ DPI-check-and-properties-code कोड लिखना होगा। नहीं भी Microsoft WinForms स्वचालित रूप से और कस्टम कीचड़ कोड के बिना, उच्च DPI सफाई से संभाल कर सकते हैं।

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

अद्यतन 2: मैं 100% / 125% डीपीआई का समर्थन कैसे करूंगा, इसके जवाब में, मैं दो-चरण की योजना बनाऊंगा। चरण 1 कस्टम नियंत्रण के लिए मेरे कोड को सूचीबद्ध करना है जो उच्च डीपीआई के लिए तय किए जाने की आवश्यकता है, और फिर उन्हें ठीक करने या उन्हें चरणबद्ध करने के लिए एक योजना बनाएं। चरण 2 मेरे कोड के कुछ क्षेत्रों को लेना होगा जो बिना लेआउट प्रबंधन के प्रपत्रों के रूप में तैयार किए गए हैं और उन्हें उन रूपों में बदल दिया है जो किसी प्रकार के लेआउट प्रबंधन का उपयोग करते हैं ताकि DPI या फ़ॉन्ट ऊंचाई परिवर्तन क्लिपिंग के बिना काम कर सकें। मुझे संदेह है कि यह "अंतर-नियंत्रण" लेआउट कार्य "इंट्रा-कंट्रोल" कार्य की तुलना में अधिकांश अनुप्रयोगों में अधिक जटिल होगा।

अपडेट: 2016 में, नवीनतम डेल्फी 10.1 बर्लिन मेरे 150 डीपीआई वर्कस्टेशन पर अच्छी तरह से काम कर रहा है।


5
वह एपीआई फंक्शन होगा SetProcessDPIAware
डेविड हेफर्नन

2
अति उत्कृष्ट। नए factoid के लिए धन्यवाद। मेरा सुझाव है कि आप अपने उत्तर को संशोधित करने के लिए सुझाव दें कि एक संभावित मार्ग के रूप में। यह हो सकता है कि ग्राहक उस विकल्प को कॉन्फ़िगर करना भी चाहें (इसे बंद कर दें यदि यह उनके लिए काम नहीं करता है)।
वारेन पी

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

6
RAD Studio मानक VCL नियंत्रण, कस्टम नियंत्रण, .NET WinForms और FireMonkey रूपों का एक बड़ा मिश्रण है। यह आश्चर्य की बात नहीं है, कि समस्याएं हैं। और यही वजह है कि RAD Studio एक अच्छा उदाहरण नहीं है।
टॉर्बिन 20

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

63

.Dfm फ़ाइल में आपकी सेटिंग्स सही ढंग से बढ़ाई जाएंगी, जब तक कि Scaledयह है True

यदि आप कोड में आयाम स्थापित कर रहे हैं तो आपको उन्हें Screen.PixelsPerInchविभाजित करके मापना होगा Form.PixelsPerInchMulDivऐसा करने के लिए उपयोग करें।

function TMyForm.ScaleDimension(const X: Integer): Integer;
begin
  Result := MulDiv(X, Screen.PixelsPerInch, PixelsPerInch);
end;

यह वही है जो फार्म दृढ़ता फ्रेमवर्क कब करता Scaledहै True

वास्तव में, आप इस फ़ंक्शन को एक ऐसे संस्करण के साथ बदलने के लिए एक तर्क कर सकते हैं जो हार्ड कोड को हर के लिए 96 का मान देता है। यह आपको पूर्ण आयाम मानों का उपयोग करने की अनुमति देता है और यदि आप अपने विकास मशीन पर फ़ॉन्ट स्केलिंग बदलने के लिए होते हैं और .dfm फ़ाइल को फिर से सहेजते हैं, तो इसे बदलने के अर्थ के बारे में चिंता न करें। इसका कारण यह है कि PixelsPerInch.dfm फ़ाइल में संग्रहीत संपत्ति उस मशीन का मान है जिस पर .dfm फ़ाइल को पिछली बार सहेजा गया था।

const
  SmallFontsPixelsPerInch = 96;

function ScaleFromSmallFontsDimension(const X: Integer): Integer;
begin
  Result := MulDiv(X, Screen.PixelsPerInch, SmallFontsPixelsPerInch);
end;

इसलिए, विषय को जारी रखना, सावधान रहने की एक और बात यह है कि यदि आपका प्रोजेक्ट अलग-अलग DPI मानों के साथ कई मशीनों पर विकसित किया गया है, तो आप पाएंगे कि बचत के दौरान डेल्फी का उपयोग करते समय स्केलिंग। । मेरे कार्यस्थल पर, इससे बचने के लिए, हमारी एक सख्त नीति है कि फॉर्म केवल 96 डीपीआई (100% स्केलिंग) पर संपादित किए जाते हैं।

वास्तव में मेरा संस्करण ScaleFromSmallFontsDimensionभी फॉर्मटाइम से भिन्न होता है जो कि फॉर्मटाइम पर सेटटाइम से भिन्न होता है। XP मशीनों पर मेरे आवेदन के फार्म 8pt तहोमा का उपयोग करते हैं। Vista और ऊपर 9pt Segoe UI का उपयोग किया जाता है। यह स्वतंत्रता की एक और डिग्री प्रदान करता है। स्केलिंग के लिए इसका हिसाब होना चाहिए क्योंकि स्रोत कोड में उपयोग किए गए निरपेक्ष आयाम मान 96dpi पर 8pt तहोमा की आधार रेखा के सापेक्ष माने जाते हैं।

यदि आप अपने यूआई में किसी भी चित्र या ग्लिफ़ का उपयोग करते हैं तो इन्हें भी स्केल करने की आवश्यकता है। एक सामान्य उदाहरण ग्लिफ़ होगा जो टूलबार और मेनू पर उपयोग किया जाता है। आप इन ग्लिफ़्स को आइकन संसाधनों के रूप में प्रदान करना चाहेंगे जो आपके निष्पादन योग्य से जुड़े हों। प्रत्येक आइकन में आकारों की एक सीमा होनी चाहिए और फिर रनटाइम में आप सबसे उपयुक्त आकार चुनते हैं और इसे एक छवि सूची में लोड करते हैं। उस विषय पर कुछ विवरण यहां मिल सकते हैं: कैसे मैं अलियासिंग से पीड़ित के बिना संसाधन से आइकन लोड कर सकता हूं?

एक अन्य उपयोगी चाल सापेक्ष इकाइयों में आयामों को परिभाषित करना है, TextWidthया के सापेक्ष TextHeight। इसलिए, यदि आप चाहते हैं कि आकार में लगभग 10 ऊर्ध्वाधर रेखाएं हों तो आप उपयोग कर सकते हैं 10*Canvas.TextHeight('Ag')। यह एक बहुत ही मोटा और तैयार मीट्रिक है क्योंकि यह लाइन रिक्ति और इतने पर अनुमति नहीं देता है। हालांकि, अक्सर आपको जो कुछ भी करने की ज़रूरत होती है, वह यह व्यवस्था करने में सक्षम होता है कि जीयूआई ठीक से मापता है PixelsPerInch

आपको अपने आवेदन को उच्च डीपीआई के रूप में जागरूक होना चाहिए । ऐसा करने का सबसे अच्छा तरीका एप्लिकेशन मैनिफ़ेस्ट है। चूंकि डेल्फी के निर्माण उपकरण आपको अपने स्वयं के प्रकट संसाधन को लिंक करने के लिए इस बल का उपयोग करने की अनुमति नहीं देते हैं।

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings
         xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>

संसाधन स्क्रिप्ट इस प्रकार दिखती है:

1 24 "Manifest.txt"

जहां Manifest.txtवास्तविक प्रकट होता है। आपको comctl32 v6 अनुभाग को शामिल करने और सेट requestedExecutionLevelकरने की भी आवश्यकता होगी asInvoker। फिर आप इस संकलित संसाधन को अपने ऐप से लिंक करते हैं और सुनिश्चित करते हैं कि डेल्फी अपने प्रकट रूप से ऐसा करने की कोशिश नहीं करता है। आधुनिक डेल्फी में आप कोई भी रनटाइम थीम प्रोजेक्ट विकल्प सेट करके प्राप्त करते हैं।

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

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

विंडोज 8.1 प्रति मॉनिटर डीपीआई अपडेट

Windows 8.1 के अनुसार, अब प्रति मॉनिटर DPI सेटिंग्स ( http://msdn.microsoft.com/en-ca/magazine/dn574798.aspx ) के लिए OS समर्थन है । यह आधुनिक उपकरणों के लिए एक बड़ा मुद्दा है जिसमें बहुत भिन्न क्षमताओं के साथ अलग-अलग डिस्प्ले हो सकते हैं। आपके पास एक बहुत ही उच्च डीपीआई लैपटॉप स्क्रीन, और एक कम डीपीआई बाहरी प्रोजेक्टर हो सकता है। इस तरह के परिदृश्य का समर्थन ऊपर वर्णित से भी अधिक काम लेता है।


2
यह हमेशा सच नहीं है। वास्तव में, स्केलिंग सेट करना = सही, और फिर हाई डीपीआई को अवगत कराना भी अधिकांश डेल्फी अनुप्रयोगों में कुछ अजीब टूटना पैदा कर सकता है। मैंने अपने ऐप्स को उच्च डीपीआई में काम करने के लिए सैकड़ों घंटे बिताने की कोशिश की है और पाया है कि क्रॉप्ड नियंत्रण, स्क्रीन को स्थानांतरित करने, विभिन्न नियंत्रणों पर अतिरिक्त या लापता स्क्रॉलबारों की तुलना में भयानक दिखने वाले पिक्सेलकरण के लिए बेहतर है, आदि
वॉरेन पी

@WarrenP मुझे लगता है कि वे समस्याएं आपके ऐप के लिए विशेष रूप से हैं। मेरा व्यक्तिगत अनुभव यह है कि मेरा डेल्फी ऐप 200% फ़ॉन्ट स्केलिंग पर भी पूरी तरह से प्रदर्शित होता है।
डेविड हेफर्नन

2
@ArrenP तो क्या? डेल्फी आईडी से बेहतर व्यवहार करने वाले ऐप बनाने के लिए डेल्फी का उपयोग करना पूरी तरह से संभव है।
डेविड हेफर्नन 16

1
मैंने डेल्फी 5,6,7 के साथ बनाए गए निश्चित सीमाओं के साथ बहुत सारे संवादों को देखा है और असफल सेटिंग को विफल करने के लिए सही है। ठीक छुपाना, बटन को रद्द करना आदि यहां तक ​​कि डेल्फी 2006 में कुछ संवादों से लगता है कि इसे काट दिया गया था। देशी डेल्फी घटकों और खिड़कियों के घटकों को मिलाकर भी अजीब प्रभाव होता है। मैं हमेशा एक 125% फ़ॉन्ट स्केलिंग में GUI विकसित करता हूं और स्केल की गई संपत्ति को झूठे में डाल देता हूं।
एलयू आरडी

2
उत्तम सामग्री। शानदार जानकारी के लिए +1। मेरी राय (ऐसा न करें) यह जानने के लिए महत्वपूर्ण है कि जब आप ऐसा करना चाहते हैं, तो यह कैसे करना है ...
वॉरेन पी

42

यह भी ध्यान रखना महत्वपूर्ण है कि उपयोगकर्ता की DPI को सम्मानित करना आपकी वास्तविक नौकरी का केवल एक सबसेट है:

उपयोगकर्ता के फ़ॉन्ट आकार का सम्मान करना

दशकों तक, विंडोज ने इस मुद्दे को पिक्सल के बजाय डायलॉग इकाइयों का उपयोग करते हुए धारणा प्रदर्शन के साथ हल किया है । एक "संवाद इकाई" को परिभाषित किया गया है ताकि फ़ॉन्ट का औसत चरित्र हो

  • 4 संवाद इकाइयाँ (dlus) चौड़ी, और
  • 8 संवाद इकाइयाँ (क्लस) ऊँची

यहां छवि विवरण दर्ज करें

डेल्फी एक (छोटी गाड़ी) धारणा के साथ जहाज करता है Scaled, जहां एक रूप के आधार पर स्वचालित रूप से समायोजित करने की कोशिश करता है

  • उपयोगकर्ता की विंडोज डीपीआई सेटिंग्स, छंद
  • डेवलपर की मशीन पर डीपीआई सेटिंग जो अंतिम रूप से फॉर्म को बचाता है

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

  • डेवलपर ने MS Sans Serif 8pt के साथ फॉर्म तैयार किया (जहां औसत चरित्र 6.21px x 13.00px96dpi पर है)
  • तहोमा 8pt के साथ चलने वाला उपयोगकर्ता (जहां औसत चरित्र 5.94px x 13.00px96dpi पर है)

    जैसा कि विंडोज 2000 या विंडोज एक्सपी के लिए एप्लिकेशन विकसित करने वाले किसी के मामले में था।

या

  • डेवलपर ने ** तहोमा 8pt * के साथ फॉर्म तैयार किया (जहाँ औसत चरित्र 5.94px x 13.00px96dpi पर है)
  • Segoe UI 9pt के साथ चलने वाला उपयोगकर्ता (जहां औसत चरित्र 6.67px x 15px96dpi पर है)

एक अच्छे डेवलपर के रूप में आप अपने उपयोगकर्ता की प्राथमिकताओं का सम्मान करने जा रहे हैं। इसका मतलब है कि आपको नए फॉण्ट के आकार से मेल खाने के लिए अपने फॉर्म पर सभी नियंत्रणों को पैमाना करना होगा:

  • 12.29% (6.67 / 5.94) द्वारा क्षैतिज रूप से सब कुछ का विस्तार करें
  • 15.38% (15/13) तक सब कुछ लंबवत रूप से फैलाएं

Scaled यह आपके लिए नहीं होगा।

यह बदतर हो जाता है जब:

  • Segoe UI 9pt (विंडोज विस्टा, विंडोज 7, विंडोज 8 डिफॉल्ट) में अपना फॉर्म डिजाइन किया
  • उपयोगकर्ता Segoe UI 14pt चला रहा है , (जैसे मेरी प्राथमिकता) जो है10.52px x 25px

अब आपको हर चीज को स्केल करना होगा

  • क्षैतिज रूप से 57.72%
  • 66.66% द्वारा लंबवत

Scaled यह आपके लिए नहीं होगा।


यदि आप होशियार हैं तो आप देख सकते हैं कि डीपीआई का सम्मान करना कितना अनुचित है:

  • Segoe UI 9pt @ 96dpi (6.67px x 15px) के साथ तैयार किया गया फॉर्म
  • Segoe UI 9pt @ 150dpi (10.52px x 25px) के साथ चलने वाला उपयोगकर्ता

आपको उपयोगकर्ता की डीपीआई सेटिंग नहीं देखनी चाहिए, आपको उनके फ़ॉन्ट आकार को देखना चाहिए । दो उपयोगकर्ता चल रहे हैं

  • Segoe UI 14pt @ 96dpi (10.52px x 25px)
  • Segoe UI 9pt @ 150dpi (10.52px x 25px)

एक ही फ़ॉन्ट चला रहे हैं । डीपीआई केवल एक चीज है जो फ़ॉन्ट आकार को प्रभावित करती है; उपयोगकर्ता की प्राथमिकताएँ अन्य हैं।

StandardizeFormFont

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

function StandardizeFormFont(AForm: TForm): Real;
var
    preferredFontName: string;
    preferredFontHeight: Integer;
begin
    GetUserFontPreference({out}preferredFontName, {out}preferredFontHeight);

    //e.g. "Segoe UI",     
    Result := Toolkit.StandardizeFormFont(AForm, PreferredFontName, PreferredFontHeight);
end;

विंडोज में 6 अलग-अलग फोंट हैं; विंडोज में एक भी "फॉन्ट सेटिंग" नहीं है।
लेकिन हम अनुभव से जानते हैं कि हमारे रूपों को आइकन शीर्षक फ़ॉन्ट सेटिंग का पालन करना चाहिए

procedure GetUserFontPreference(out FaceName: string; out PixelHeight: Integer);
var
   font: TFont;
begin
   font := Toolkit.GetIconTitleFont;
   try
      FaceName := font.Name; //e.g. "Segoe UI"

      //Dogfood testing: use a larger font than we're used to; to force us to actually test it    
      if IsDebuggerPresent then
         font.Size := font.Size+1;

      PixelHeight := font.Height; //e.g. -16
   finally
      font.Free;
   end;
end;

एक बार जब हम फ़ॉन्ट आकार को जान लेते हैं , तो हम फ़ॉर्म को स्केल कर देंगे , हमें फॉर्म की वर्तमान फ़ॉन्ट ऊँचाई ( पिक्सेल में ) मिल जाएगी, और उस कारक द्वारा स्केल कर दी जाएगी।

उदाहरण के लिए, यदि मैं -16वर्तमान में फॉर्म सेट कर रहा हूं , और फॉर्म वर्तमान में है -11, तो हमें पूरे फॉर्म को निम्नानुसार स्केल करना होगा:

-16 / -11 = 1.45454%

मानकीकरण दो चरणों में होता है। पहले फॉर्म को नए: पुराने फॉन्ट साइज के अनुपात से स्केल करें। फिर नए फ़ॉन्ट का उपयोग करने के लिए वास्तव में नियंत्रण (पुनरावर्ती) बदलें।

function StandardizeFormFont(AForm: TForm; FontName: string; FontHeight: Integer): Real;
var
    oldHeight: Integer;
begin
    Assert(Assigned(AForm));

    if (AForm.Scaled) then
    begin
        OutputDebugString(PChar('WARNING: StandardizeFormFont: Form "'+GetControlName(AForm)+'" is set to Scaled. Proper form scaling requires VCL scaling to be disabled, unless you implement scaling by overriding the protected ChangeScale() method of the form.'));
    end;

    if (AForm.AutoScroll) then
    begin
        if AForm.WindowState = wsNormal then
        begin
            OutputDebugString(PChar('WARNING: StandardizeFormFont: Form "'+GetControlName(AForm)+'" is set to AutoScroll. Form designed size will be suseptable to changes in Windows form caption height (e.g. 2000 vs XP).'));
                    if IsDebuggerPresent then
                        Windows.DebugBreak; //Some forms would like it (to fix maximizing problem)
        end;
    end;

    if (not AForm.ShowHint) then
    begin
        AForm.ShowHint := True;
        OutputDebugString(PChar('INFORMATION: StandardizeFormFont: Turning on form "'+GetControlName(AForm)+'" hints. (ShowHint := True)'));
                    if IsDebuggerPresent then
                        Windows.DebugBreak; //Some forms would like it (to fix maximizing problem)
    end;

    oldHeight := AForm.Font.Height;

    //Scale the form to the new font size
//  if (FontHeight <> oldHeight) then    For compatibility, it's safer to trigger a call to ChangeScale, since a lot of people will be assuming it always is called
    begin
        ScaleForm(AForm, FontHeight, oldHeight);
    end;

    //Now change all controls to actually use the new font
    Toolkit.StandardizeFont_ControlCore(AForm, g_ForceClearType, FontName, FontHeight,
            AForm.Font.Name, AForm.Font.Size);

    //Return the scaling ratio, so any hard-coded values can be multiplied
    Result := FontHeight / oldHeight;
end;

यहाँ वास्तव में एक फार्म स्केलिंग का काम है। यह बोरलैंड की अपनी Form.ScaleByविधि में बग के आसपास काम करता है । पहले इसे फॉर्म पर सभी एंकर को निष्क्रिय करना होगा, फिर स्केलिंग प्रदर्शन करना होगा, फिर एंकर को फिर से सक्षम करना होगा:

TAnchorsArray = array of TAnchors;

procedure ScaleForm(const AForm: TForm; const M, D: Integer);
var
    aAnchorStorage: TAnchorsArray;
    RectBefore, RectAfter: TRect;
    x, y: Integer;
    monitorInfo: TMonitorInfo;
    workArea: TRect;
begin
    if (M = 0) and (D = 0) then
        Exit;

    RectBefore := AForm.BoundsRect;

    SetLength(aAnchorStorage, 0);
    aAnchorStorage := DisableAnchors(AForm);
    try
        AForm.ScaleBy(M, D);
    finally
        EnableAnchors(AForm, aAnchorStorage);
    end;

    RectAfter := AForm.BoundsRect;

    case AForm.Position of
    poScreenCenter, poDesktopCenter, poMainFormCenter, poOwnerFormCenter,
    poDesigned: //i think i really want everything else to also follow the nudging rules...why did i exclude poDesigned
        begin
            //This was only nudging by one quarter the difference, rather than one half the difference
//          x := RectAfter.Left - ((RectAfter.Right-RectBefore.Right) div 2);
//          y := RectAfter.Top - ((RectAfter.Bottom-RectBefore.Bottom) div 2);
            x := RectAfter.Left - ((RectAfter.Right-RectAfter.Left) - (RectBefore.Right-RectBefore.Left)) div 2;
            y := RectAfter.Top - ((RectAfter.Bottom-RectAfter.Top)-(RectBefore.Bottom-RectBefore.Top)) div 2;
        end;
    else
        //poDesigned, poDefault, poDefaultPosOnly, poDefaultSizeOnly:
        x := RectAfter.Left;
        y := RectAfter.Top;
    end;

    if AForm.Monitor <> nil then
    begin
        monitorInfo.cbSize := SizeOf(monitorInfo);
        if GetMonitorInfo(AForm.Monitor.Handle, @monitorInfo) then
            workArea := monitorInfo.rcWork
        else
        begin
            OutputDebugString(PChar(SysErrorMessage(GetLastError)));
            workArea := Rect(AForm.Monitor.Left, AForm.Monitor.Top, AForm.Monitor.Left+AForm.Monitor.Width, AForm.Monitor.Top+AForm.Monitor.Height);
        end;

//      If the form is off the right or bottom of the screen then we need to pull it back
        if RectAfter.Right > workArea.Right then
            x := workArea.Right - (RectAfter.Right-RectAfter.Left); //rightEdge - widthOfForm

        if RectAfter.Bottom > workArea.Bottom then
            y := workArea.Bottom - (RectAfter.Bottom-RectAfter.Top); //bottomEdge - heightOfForm

        x := Max(x, workArea.Left); //don't go beyond left edge
        y := Max(y, workArea.Top); //don't go above top edge
    end
    else
    begin
        x := Max(x, 0); //don't go beyond left edge
        y := Max(y, 0); //don't go above top edge
    end;

    AForm.SetBounds(x, y,
            RectAfter.Right-RectAfter.Left, //Width
            RectAfter.Bottom-RectAfter.Top); //Height
end;

और फिर हमें नए फ़ॉन्ट का पुनरावर्ती उपयोग करना होगा:

procedure StandardizeFont_ControlCore(AControl: TControl; ForceClearType: Boolean;
        FontName: string; FontSize: Integer;
        ForceFontIfName: string; ForceFontIfSize: Integer);
const
    CLEARTYPE_QUALITY = 5;
var
    i: Integer;
    RunComponent: TComponent;
    AControlFont: TFont;
begin
    if not Assigned(AControl) then
        Exit;

    if (AControl is TStatusBar) then
    begin
        TStatusBar(AControl).UseSystemFont := False; //force...
        TStatusBar(AControl).UseSystemFont := True;  //...it
    end
    else
    begin
        AControlFont := Toolkit.GetControlFont(AControl);

        if not Assigned(AControlFont) then
            Exit;

        StandardizeFont_ControlFontCore(AControlFont, ForceClearType,
                FontName, FontSize,
                ForceFontIfName, ForceFontIfSize);
    end;

{   If a panel has a toolbar on it, the toolbar won't paint properly. So this idea won't work.
    if (not Toolkit.IsRemoteSession) and (AControl is TWinControl) and (not (AControl is TToolBar)) then
        TWinControl(AControl).DoubleBuffered := True;
}

    //Iterate children
    for i := 0 to AControl.ComponentCount-1 do
    begin
        RunComponent := AControl.Components[i];
        if RunComponent is TControl then
            StandardizeFont_ControlCore(
                    TControl(RunComponent), ForceClearType,
                    FontName, FontSize,
                    ForceFontIfName, ForceFontIfSize);
    end;
end;

एंकरों को पुन: अक्षम किया जा रहा है:

function DisableAnchors(ParentControl: TWinControl): TAnchorsArray;
var
    StartingIndex: Integer;
begin
    StartingIndex := 0;
    DisableAnchors_Core(ParentControl, Result, StartingIndex);
end;


procedure DisableAnchors_Core(ParentControl: TWinControl; var aAnchorStorage: TAnchorsArray; var StartingIndex: Integer);
var
    iCounter: integer;
    ChildControl: TControl;
begin
    if (StartingIndex+ParentControl.ControlCount+1) > (Length(aAnchorStorage)) then
        SetLength(aAnchorStorage, StartingIndex+ParentControl.ControlCount+1);

    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        aAnchorStorage[StartingIndex] := ChildControl.Anchors;

        //doesn't work for set of stacked top-aligned panels
//      if ([akRight, akBottom ] * ChildControl.Anchors) <> [] then
//          ChildControl.Anchors := [akLeft, akTop];

        if (ChildControl.Anchors) <> [akTop, akLeft] then
            ChildControl.Anchors := [akLeft, akTop];

//      if ([akTop, akBottom] * ChildControl.Anchors) = [akTop, akBottom] then
//          ChildControl.Anchors := ChildControl.Anchors - [akBottom];

        Inc(StartingIndex);
    end;

    //Add children
    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        if ChildControl is TWinControl then
            DisableAnchors_Core(TWinControl(ChildControl), aAnchorStorage, StartingIndex);
    end;
end;

और लंगर फिर से सक्षम किया जा रहा है:

procedure EnableAnchors(ParentControl: TWinControl; aAnchorStorage: TAnchorsArray);
var
    StartingIndex: Integer;
begin
    StartingIndex := 0;
    EnableAnchors_Core(ParentControl, aAnchorStorage, StartingIndex);
end;


procedure EnableAnchors_Core(ParentControl: TWinControl; aAnchorStorage: TAnchorsArray; var StartingIndex: Integer);
var
    iCounter: integer;
    ChildControl: TControl;
begin
    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        ChildControl.Anchors := aAnchorStorage[StartingIndex];

        Inc(StartingIndex);
    end;

    //Restore children
    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        if ChildControl is TWinControl then
            EnableAnchors_Core(TWinControl(ChildControl), aAnchorStorage, StartingIndex);
    end;
end;

वास्तव में एक नियंत्रण फ़ॉन्ट बदलने के काम के साथ छोड़ दिया:

procedure StandardizeFont_ControlFontCore(AControlFont: TFont; ForceClearType: Boolean;
        FontName: string; FontSize: Integer;
        ForceFontIfName: string; ForceFontIfSize: Integer);
const
    CLEARTYPE_QUALITY = 5;
var
    CanChangeName: Boolean;
    CanChangeSize: Boolean;
    lf: TLogFont;
begin
    if not Assigned(AControlFont) then
        Exit;

{$IFDEF ForceClearType}
    ForceClearType := True;
{$ELSE}
    if g_ForceClearType then
        ForceClearType := True;
{$ENDIF}

    //Standardize the font if it's currently
    //  "MS Shell Dlg 2" (meaning whoever it was opted into the 'change me' system
    //  "MS Sans Serif" (the Delphi default)
    //  "Tahoma" (when they wanted to match the OS, but "MS Shell Dlg 2" should have been used)
    //  "MS Shell Dlg" (the 9x name)
    CanChangeName :=
            (FontName <> '')
            and
            (AControlFont.Name <> FontName)
            and
            (
                (
                    (ForceFontIfName <> '')
                    and
                    (AControlFont.Name = ForceFontIfName)
                )
                or
                (
                    (ForceFontIfName = '')
                    and
                    (
                        (AControlFont.Name = 'MS Sans Serif') or
                        (AControlFont.Name = 'Tahoma') or
                        (AControlFont.Name = 'MS Shell Dlg 2') or
                        (AControlFont.Name = 'MS Shell Dlg')
                    )
                )
            );

    CanChangeSize :=
            (
                //there is a font size
                (FontSize <> 0)
                and
                (
                    //the font is at it's default size, or we're specifying what it's default size is
                    (AControlFont.Size = 8)
                    or
                    ((ForceFontIfSize <> 0) and (AControlFont.Size = ForceFontIfSize))
                )
                and
                //the font size (or height) is not equal
                (
                    //negative for height (px)
                    ((FontSize < 0) and (AControlFont.Height <> FontSize))
                    or
                    //positive for size (pt)
                    ((FontSize > 0) and (AControlFont.Size <> FontSize))
                )
                and
                //no point in using default font's size if they're not using the face
                (
                    (AControlFont.Name = FontName)
                    or
                    CanChangeName
                )
            );

    if CanChangeName or CanChangeSize or ForceClearType then
    begin
        if GetObject(AControlFont.Handle, SizeOf(TLogFont), @lf) <> 0 then
        begin
            //Change the font attributes and put it back
            if CanChangeName then
                StrPLCopy(Addr(lf.lfFaceName[0]), FontName, LF_FACESIZE);
            if CanChangeSize then
                lf.lfHeight := FontSize;

            if ForceClearType then
                lf.lfQuality := CLEARTYPE_QUALITY;
            AControlFont.Handle := CreateFontIndirect(lf);
        end
        else
        begin
            if CanChangeName then
                AControlFont.Name := FontName;
            if CanChangeSize then
            begin
                if FontSize > 0 then
                    AControlFont.Size := FontSize
                else if FontSize < 0 then
                    AControlFont.Height := FontSize;
            end;
        end;
    end;
end;

यह एक बहुत अधिक कोड है जितना आपने सोचा था कि यह होने जा रहा था; मुझे पता है। दुःख की बात यह है कि पृथ्वी पर कोई डेल्फी डेवलपर नहीं है, मेरे अलावा, जो वास्तव में अपने अनुप्रयोगों को सही बनाता है।

प्रिय डेल्फी डेवलपर : Segoe UI 14pt के लिए अपना विंडोज फ़ॉन्ट सेट करें , और अपने छोटी गाड़ी के आवेदन को ठीक करें

नोट : कोई भी कोड सार्वजनिक डोमेन में जारी किया जाता है। कोई एट्रिब्यूशन की आवश्यकता नहीं है।


1
उत्तर के लिए धन्यवाद, लेकिन आप वास्तविक दुनिया के लिए क्या सुझाव देते हैं? मैन्युअल रूप से सभी नियंत्रणों के आकार को लागू करें?
लाब्राका

3
"दुख की बात यह है कि पृथ्वी पर कोई डेल्फी डेवलपर नहीं है, मेरे अलावा, जो वास्तव में अपने अनुप्रयोगों को सही बनाता है।" यह एक बहुत ही घमंडी बयान है जो गलत है। मेरे उत्तर से: वास्तव में स्केल के मेरे संस्करण ScaleFromSmallFontsDimension भी उस प्रपत्र से रनटाइम में भिन्न रूप में पदनाम की संभावना के लिए भत्ता बनाता है। स्केलिंग के लिए इसका हिसाब होना चाहिए क्योंकि स्रोत कोड में उपयोग किए गए पूर्ण आयाम मान 96dpi पर 8pt तहोमा की आधार रेखा के सापेक्ष माने जाते हैं। आपका उत्तर एक अच्छा जवाब है, आप, +1।
डेविड हेफर्नन

1
@ इयान ने मुझे नहीं कहा। वॉरेन की तरह लगता है।
डेविड हेफर्नन

2
यह काफी भयानक है, इयान। धन्यवाद।
वॉरेन पी।

2
हाल ही में इस सवाल और जवाब पर दौड़ा। मैंने सभी इयान के कोड को एक कार्यकारी इकाई में यहां एकत्र किया है: pastebin.com/dKpfnXLc और इसे यहां Google+ पर पोस्ट किया है: goo.gl/0ARdq9 किसी के भी उपयोगी होने की स्थिति में यहां पोस्ट करना।
डब्ल्यू। सिन्स

11

यहाँ मेरा उपहार है। एक फ़ंक्शन जो आपके GUI लेआउट में तत्वों की क्षैतिज स्थिति के साथ मदद कर सकता है। सभी के लिए नि: शुल्क।

function CenterInParent(Place,NumberOfPlaces,ObjectWidth,ParentWidth,CropPercent: Integer): Integer;
  {returns formated centered position of an object relative to parent.
  Place          - P order number of an object beeing centered
  NumberOfPlaces - NOP total number of places available for object beeing centered
  ObjectWidth    - OW width of an object beeing centered
  ParentWidth    - PW width of an parent
  CropPercent    - CP percentage of safe margin on both sides which we want to omit from calculation
  +-----------------------------------------------------+
  |                                                     |
  |        +--------+       +---+      +--------+       |
  |        |        |       |   |      |        |       |
  |        +--------+       +---+      +--------+       |
  |     |              |             |            |     |
  +-----------------------------------------------------+
  |     |<---------------------A----------------->|     |
  |<-C->|<------B----->|<-----B----->|<-----B---->|<-C->|
  |                    |<-D>|
  |<----------E------------>|

  A = PW-C   B = A/NOP  C=(CP*PW)/100  D = (B-OW)/2
  E = C+(P-1)*B+D }

var
  A, B, C, D: Integer;
begin
  C := Trunc((CropPercent*ParentWidth)/100);
  A := ParentWidth - C;
  B := Trunc(A/NumberOfPlaces);
  D := Trunc((B-ObjectWidth)/2);
  Result := C+(Place-1)*B+D;
end;

2
मुझे खुशी है कि आपको वॉरेन पसंद है। यह लगभग 15 साल पुराना है जब मुझे उस समस्या का कोई समाधान उपलब्ध नहीं था जिसे मुझे हल करना था। और आज भी ऐसी स्थिति हो सकती है जहां इसे लागू किया जा सकता है। बी-)
अवरा डे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.