2025, Oct 04 15:31

Gtk FileChooserDialog का आकार क्यों बिगड़ता है और इसे सही कैसे करें

Ubuntu 24.04 में Gtk FileChooserDialog अपेक्षित ऊँचाई पर नहीं खुल रहा? show सिग्नल पर resize(width,height) कॉल करें, -1 से बचें और याद रखे आकार को ओवरराइड कर स्थिर, रीसाइज़ेबल डायलॉग पाएं.

अनुरोधित आकार पर न टिकने वाला Gtk.FileChooserDialog उलझन में डाल सकता है, खासकर जब कागज़ पर सब कुछ सही दिखता हो। अगर आपका डायलॉग मांगे गए से ज्यादा ऊँचाई में खुलता है, पहली बार हाथ से रीसाइज़ करते ही बहुत छोटे दृश्य पर उछल जाता है, या बार‑बार पुरानी ज्योमेट्री वापस ले आता है, तो आप याद रखे गए विंडो आकार और आकार कब लागू किया जा रहा है—इन दोनों के मेल से टकरा रहे हैं।

समस्या का उदाहरण

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

import sys
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gtk
class Picker(Gtk.FileChooserDialog):
    def __init__(self, title=None, parent=None):
        super().__init__(
            title=title,
            parent=parent,
            action=Gtk.FileChooserAction.OPEN,
            default_height=500,
        )
        self.set_default_size(-1, 500)
        self.set_size_request(-1, 300)
        self.add_buttons(
            Gtk.STOCK_CANCEL,
            Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN,
            Gtk.ResponseType.OK,
        )
        self._install_filters()
        self._run_dialog()
    def _install_filters(self):
        txt_filter = Gtk.FileFilter()
        txt_filter.set_name(".txt files")
        txt_filter.add_mime_type("text")
        self.add_filter(txt_filter)
    def _run_dialog(self):
        result = self.run()
        self.destroy()
class DemoApp(Gtk.Application):
    def __init__(self):
        super().__init__(application_id="com.gnome.test")
        GLib.set_application_name("test")
    def do_activate(self):
        self.win = Gtk.ApplicationWindow(application=self, title="App")
        grid = Gtk.Grid()
        self.win.add(grid)
        btn = Gtk.Button(label="From")
        grid.attach(btn, 0, 0, 1, 1)
        grid.set_row_homogeneous(True)
        grid.set_column_homogeneous(True)
        btn.connect("clicked", self._on_pick)
        self.win.set_default_size(width=500, height=34)
        self.win.show_all()
    def _on_pick(self, _widget):
        picker = Picker(title="Chooser", parent=self.win)
        picker.set_default_size(-1, 400)
app = DemoApp()
code = app.run(sys.argv)
sys.exit(code)

क्या हो रहा है

दो महत्वपूर्ण बातें हैं। पहला, Ubuntu 24.04 आधारित सिस्टमों पर डायलॉग अपना पिछला आकार याद रख सकता है और run() उस सहेजी गई ज्योमेट्री को लागू कर सकता है, जिससे पहले मांगे गए आयाम ओवरराइड हो जाते हैं। दूसरा, किसी एक आयाम के लिए -1 का प्रयोग इस स्थिति में अपेक्षित नतीजे में बाधा डालता है। यही वजह है कि डायलॉग माँगी गई ऊँचाई से ज़्यादा पर खुलता है और पहली मैन्युअल रीसाइज़ पर अचानक बहुत छोटे दृश्य पर कूद सकता है, मानो सिर्फ़ कोई चाइल्ड विजेट ही दिख रहा हो।

set_resizable(False) के साथ फ़िक्स्ड आकार थोपने पर अपेक्षित ज्योमेट्री मिल जाती है, लेकिन मैन्युअल रीसाइज़िंग असंभव हो जाती है—जो फ़ाइल चुज़र के लिए शायद ही कभी वांछनीय है।

पर्यावरण-विशिष्ट एक पहलू और भी है। Ubuntu 24.04 पर आधारित Linux Mint में MATE के साथ चलाने पर सिस्टम स्क्रिप्ट के अलग‑अलग रन में भी डायलॉग का आकार याद रखता है और उसे वापस लागू कर देता है, जिससे आपके सेट करने के बाद भी आकार बदल सकता है।

समाधान

आकार का फ़ैसला जितना संभव हो उतना देर से करें और इस परिदृश्य में आयामों के लिए -1 से बचें। show सिग्नल से जुड़कर और resize(width, height) को दोनों मान स्पष्ट रूप से देकर कॉल करने से यह सुनिश्चित होता है कि पहले से याद रखी गई ज्योमेट्री लागू होने के बाद डायलॉग आपका आकार अपनाए। इससे पहली रीसाइज़ गड़बड़ी नहीं होती और आपको एक रीसाइज़ेबल विंडो मिलती है। यहां set_default_size और set_size_request को कॉल करने की ज़रूरत नहीं है।

import sys
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gtk
class PickerFixed(Gtk.FileChooserDialog):
    def __init__(self, title=None, parent=None):
        super().__init__(
            title=title,
            parent=parent,
            action=Gtk.FileChooserAction.OPEN,
        )
        self.add_buttons(
            Gtk.STOCK_CANCEL,
            Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN,
            Gtk.ResponseType.OK,
        )
        self._apply_filters()
        self.connect("show", self._on_show)
        self._open()
    def _apply_filters(self):
        txt_filter = Gtk.FileFilter()
        txt_filter.set_name(".txt files")
        txt_filter.add_mime_type("text")
        self.add_filter(txt_filter)
    def _on_show(self, *_args):
        self.resize(800, 500)
    def _open(self):
        result = self.run()
        self.destroy()
class DemoApp(Gtk.Application):
    def __init__(self):
        super().__init__(application_id="com.gnome.test")
        GLib.set_application_name("test")
    def do_activate(self):
        self.win = Gtk.ApplicationWindow(application=self, title="App")
        grid = Gtk.Grid()
        self.win.add(grid)
        btn = Gtk.Button(label="From")
        grid.attach(btn, 0, 0, 1, 1)
        grid.set_row_homogeneous(True)
        grid.set_column_homogeneous(True)
        btn.connect("clicked", self._trigger")
        self.win.set_default_size(width=500, height=34)
        self.win.show_all()
    def _trigger(self, _w):
        PickerFixed(title="Chooser", parent=self.win)
app = DemoApp()
exit_code = app.run(sys.argv)
sys.exit(exit_code)

क्यों मायने रखता है

फ़ाइल पिकर ऐसी UI हैं जिनके साथ उपयोगकर्ताओं की मसल‑मेमोरी जुड़ी होती है। लोग पूर्वानुमेय आकार और प्रतिक्रियाशील रीसाइज़िंग की उम्मीद करते हैं, ख़ासकर आधुनिक डेस्कटॉप पर जहां थीम और DE नीतियाँ अलग‑अलग होती हैं। सही समय पर आकार का नियंत्रण देना अप्रत्याशित उछालों को रोकता है, उपयोगकर्ता की मंशा का सम्मान करता है, और वातावरण‑स्तरीय ज्योमेट्री रिकॉल से बचाता है जो पहली रीसाइज़ या अलग‑अलग रन में आपको चौंका सकता है।

मुख्य बातें

यदि डायलॉग गलत ऊँचाई पर खुलता है या पहली रीसाइज़ पर अनपेक्षित रूप से सिमट जाता है, तो मान लें कि run() पहले से याद रखा गया आकार लागू कर रहा है। show पर अपनी ज्योमेट्री लागू करें और निर्धारक व्यवहार के लिए resize में चौड़ाई और ऊँचाई दोनों निर्दिष्ट करें। इस केस में आयामों के लिए -1 से बचें। set_resizable(False) आकार को मजबूर करेगा, लेकिन मैन्युअल रीसाइज़ हट जाएगा—इसे केवल वहीं रखें जहाँ फ़िक्स्ड डायलॉग स्वीकार्य हो।

यह लेख StackOverflow पर प्रश्न (लेखक: Sun Bear) और furas के उत्तर पर आधारित है।