Размер кадра Tkinter определяется как часть размера родительского кадра - PullRequest
0 голосов
/ 07 мая 2020

Я пытаюсь создать простой пользовательский интерфейс в Tkinter, и у меня возникла проблема. Я создаю настраиваемый объект Frame как вкладку в блокноте в общем приложении, а настраиваемый объект Frame определяет сетку, содержащую набор элементов управления слева и другой блокнот справа. Элемент управления Frame правильно устанавливается равным трети ширины родительского кадра, но Notebook начинается только с половиной ширины. Если я нажму кнопку, которая создает больше вкладок и добавляет их в Блокнот, ширина Блокнота увеличивается до тех пор, пока фрейм управления не станет непригодным для использования. Как мне определить такие вещи, чтобы контрольный фрейм всегда составлял точно, скажем, 30% ширины родительского фрейма, а блокнот - 70% ширины, даже если размер родительского фрейма изменяется?

Root .py

    from tkinter import *
    from tkinter.ttk import *
    from tkinter import filedialog
    import os

    from IndexFrame import IndexFrame

    root = Tk()
    root.option_add('*tearOff', FALSE)
    root.title('Test')
    width, height = root.winfo_screenwidth(), root.winfo_screenheight()
    root.geometry("%dx%d+0+0" % (width, height))
    root.grid_propagate(0)
    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)

    menubar = Menu(root)
    root['menu'] = menubar

    menu_app = Menu(menubar)
    menubar.add_cascade(menu=menu_app, label='App')

    tabs = Notebook(root)
    tabs.grid(row=0, column=0, sticky='nesw')

    def openIndex():
        dir = filedialog.askdirectory()
        tab = IndexFrame(root, dir)
        tabs.add(tab, text=os.path.split(dir)[1])
    menu_app.add_command(label='Open Index', command=openIndex)

    def closeApp():
        root.destroy()
    menu_app.add_command(label='Close', command=closeApp)

    menu_index = Menu(menubar)
    menubar.add_cascade(menu=menu_index, label='Index')

    def closeIndex():
        tabs.forget(tabs.index('current'))
    menu_index.add_command(label='Close Index', command=closeIndex)

    menu_results = Menu(menubar)
    menubar.add_cascade(menu=menu_results, label='Results')

    def closeResults():
        tabs.nametowidget(tabs.select()).closeResults()
    menu_results.add_command(label='Close Results', command=closeResults)

    root.mainloop()

IndexFrame.py (вам может потребоваться удалить код Lucene, если вы хотите запустить его, если у вас не установлен PyLucene)

    from tkinter import *
    from tkinter import filedialog
    from tkinter.ttk import *
    from tkinterhtml import HtmlFrame
    import lucene
    from lucene import *

    from java.io import File
    from java.lang import Integer
    from org.apache.lucene.analysis.standard import StandardAnalyzer
    from org.apache.lucene.index import IndexReader, DirectoryReader
    from org.apache.lucene.search import IndexSearcher, BooleanClause
    from org.apache.lucene.queryparser.classic import MultiFieldQueryParser
    from org.apache.lucene.store import FSDirectory

    from ScrollText import ScrollText

    class IndexFrame(Frame):#(PanedWindow):

        def __init__(self, parent, dirPath):
        Frame.__init__(self, parent)

        lucene.initVM()
        analyzer = StandardAnalyzer()
        indexPath = File(dirPath).toPath()
        indexDir = FSDirectory.open(indexPath)
        reader = DirectoryReader.open(indexDir)
        searcher = IndexSearcher(reader)

        self.grid_propagate(0)

        queryFrame = Frame(self)
        queryFrame.grid(row=0, column=0, sticky='nsw')

        self.resultsTabs = Notebook(self)
        self.resultsTabs.grid(row=0, column=1, sticky='nesw')

        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=3)

        label = Label(queryFrame, text="Contains " + str(reader.numDocs()) + " indexed documents")
        label.grid(row=0, column=0, columnspan=3, sticky='nesw')

        text = ScrollText(queryFrame)
        text.grid(row=2, column=0, columnspan=3, sticky='nesw')

        def save_btn():
            fname = filedialog.asksaveasfilename(title="Save query", filetypes=(("text files", "*.txt"),))
            if fname:
                file = open(fname, 'w')
                file.write(text.text.get('1.0', 'end'))
                file.close()
        save = Button(queryFrame, text='Save', command=save_btn)
        save.grid(row=1, column=0, sticky='ew')

        def load_btn():
            fname = filedialog.askopenfilename(title="Load query", filetypes=(("text files", "*.txt"),))
            if fname:
                text.text.delete('1.0', 'end')
                file = open(fname, 'r')
                text.text.insert('1.0', file.read())
                file.close()
        load = Button(queryFrame, text='Load', command=load_btn)
        load.grid(row=1, column=1, sticky='ew')

        def clear_btn():
            text.text.delete('1.0', 'end')
        clear = Button(queryFrame, text='Clear', command=clear_btn)
        clear.grid(row=1, column=2, sticky='ew')

        def search_btn():
            queryText = text.text.get('1.0', 'end')
            fields =["title", "abstract", "keywords"]
            flags = [BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD]
            query = MultiFieldQueryParser.parse(queryText, fields, flags, analyzer)
            docs = searcher.search(query, Integer.MAX_VALUE)

            tab = Frame(self.resultsTabs)

            resultsLabel = Label(tab, text="{} => {} results".format(queryText, len(docs.scoreDocs)))
            resultsLabel.grid(row=0, column=0, sticky='ew')

            htmlText = HtmlFrame(tab, vertical_scrollbar="auto")
            htmlText.grid(row=1, column=0, sticky='nesw')

            html = "<html>"
            doc = searcher.doc(docs.scoreDocs[0].doc)
            html += "<h2>Title: {}</h2></br>".format(doc.getField("title").stringValue())
            #html += "<h4>Abstract: {}</h4></br>".format(doc.getField("abstract").stringValue())
            html += "</html>"
            htmlText.set_content(html)

            self.resultsTabs.add(tab, text=str(len(docs.scoreDocs)))

        search = Button(queryFrame, text='Search', command=search_btn)
        search.grid(row=3, column=0, columnspan=3, sticky='ew')

        queryFrame.grid_rowconfigure(0, weight=0)
        queryFrame.grid_rowconfigure(1, weight=0)
        queryFrame.grid_rowconfigure(2, weight=1)
        queryFrame.grid_rowconfigure(3, weight=0)
        queryFrame.grid_columnconfigure(0, weight=1)
        queryFrame.grid_columnconfigure(1, weight=1)
        queryFrame.grid_columnconfigure(2, weight=1)

        def closeResults(self):
        self.resultsTabs.forget(self.resultsTabs.index('current'))

ScrollText.py

    from tkinter import *
    from tkinter.ttk import *

    class ScrollText(Frame):

        def __init__(self, parent=None):
            Frame.__init__(self, parent)

            self.text = Text(self)
            self.text.grid(row=0, column=0, sticky='nesw')

            yscroll = Scrollbar(self, orient=VERTICAL, command=self.text.yview)
            yscroll.grid(row=0, column=1, sticky='nesw')
            self.text.configure(yscrollcommand=yscroll.set)

            self.grid_rowconfigure(0, weight=1)
            self.grid_columnconfigure(0, weight=1)
            self.grid_columnconfigure(1, weight=0)

Я тоже рад получить общий совет Python. У меня нет большого опыта создания приложений Python, которые включают более одного файла / класса, поэтому я уверен, что делаю много чего неправильно (особенно уверен, что я неправильно делю подклассы ).

Спасибо.

1 Ответ

1 голос
/ 08 мая 2020

Воспользуйтесь менеджером .place().

Менеджер .place() - один из трех менеджеров геометрии в tkinter.

У него много аргументов, но я думаю, что есть 3, которые могут вам понадобиться.

Первый - relheight. Это означает «относительную высоту», и, как следует из названия, устанавливает высоту виджета относительно высоты главного виджета.

Например, если вы установите для параметра relheight значение 0,6, то высота виджета, который вы задали, останется равной 60% от высоты главного виджета.

Второй аргумент - relwidth. Этот работает так же, как relheight, только работает с шириной, а не с высотой.

Последний - anchor. Этот не так полезен, как два предыдущих, но в некоторых случаях очень удобен. anchor устанавливает позицию размещения. Например, если anchor был «центром», то координата, которую вы указали в функции размещения с помощью relx и rely, будет в центре этого виджета.

Конечно, это очень простое c объяснение, но другие параметры, такие как relx и rely, описаны в документации.

Подробнее о месте читайте здесь .

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...