Найти - Пользователи
Полная версия: PyQt4 добавление виджена в QMdiArea
Начало » GUI » PyQt4 добавление виджена в QMdiArea
1
tiglon
Доброго времени суток, есть вот такой код :

from PyQt4 import QtCore, QtGui
import sys
class MyWidgetKomand(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.label = QtGui.QLabel("")
        self.box = QtGui.QVBoxLayout()
        self.box.addWidget(self.label)
        self.setLayout(self.box)
class MyWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.mdi_area = QtGui.QMdiArea()
        self.setCentralWidget(self.mdi_area)
        self.add_menu()
        
        
    def add_menu(self):
        self.menuStat = QtGui.QMenu("&Статистика")
        self.actKomand = QtGui.QAction("&Командировки", None)
        self.actKomand.triggered.connect(self.on_komand)
        self.menuStat.addAction(self.actKomand)
        self.menuBar().addMenu(self.menuStat)
    
    def on_komand(self):
        komand = MyWidgetKomand()
        subWindow = self.mdi_area.addSubWindow(komand)
        subWindow.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        subWindow.resize(600, 250)
        subWindow.setWindowTitle("Командировки")
        subWindow.show()
app = QtGui.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle("")
window.resize(700, 350)
window.show()
sys.exit(app.exec_())

Вопрос в следующем, как сделать что-бы метод on_komand создавал окно только при первичном вызове, а при последующих:
1. Если окно существует - делал его активным.
2. Если окно было закрыто - открывал его снова.

Я понимаю что нужно использовать метод setActiveSubWindow(), но как реализовать логику проверки. В меню будут и другие пункты.

reclosedev
tiglon
В меню будут и другие пункты.
Нужно сначала понять, насколько будет отличаться создание этих окон.
А потом уже можно сохранять subWindow в словаре с определенным ключом.
    def __init__(self, parent=None):
        self._opened_windows = {}
        ...
 
    def on_komand(self):
        key = "Командировки"
        subWindow = self._opened_windows.get(key)
        if subWindow:
            self.mdi_area.setActiveSubWindow(subWindow)
            return
        komand = MyWidgetKomand()
        subWindow = self._opened_windows[key] = self.mdi_area.addSubWindow(komand)
        subWindow.setWindowTitle(key)
        ...
В зависимости от того насколько отличается создание разных окон для разных команд меню, ключом могут быть разные вещи, например если все отличие в заголовке:
import functools
...
self.actKomand.triggered.connect(functools.partial(self.on_komand, "Командировки"))
...
def on_komand(self, key):
    ...
или может быть создаются разные виджеты, тогда есть смысл передавать тип виджета (или фабрику, которая создаст виджет).
class MyWidgetKomand(QtGui.QWidget):
     ...
class MyWidgetAnotherKomand(QtGui.QWidget):
     ...
self.actKomand.triggered.connect(functools.partial(self.on_komand, MyWidgetKomand))
self.actKomand2.triggered.connect(functools.partial(self.on_komand, MyWidgetAnotherKomand))
...
def on_komand(self, widget_type):
     subWindow = self._opened_windows.get(widget_type)
     ...
     komand = widget_type()
     ...
tiglon
Спасибо за ответ,
да, виджеты должны быть разные. Например оба виджета это выгрузки из бд, первый с возможностью изменений значений а второй строиться на основании показателей из первого виджета.

Вариант с фабрикой мне кажется идеально подходит, но если я закрываю область, повторно при вызове из меню она не открывается (ошибка в self.mdi_area.setActiveSubWindow(subWindow) - workspace is empty)

from PyQt4 import QtCore, QtGui
import sys
from functools import partial
class MyWidgetKomand(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.tname = "Командировки"
        self.label = QtGui.QLabel("")
        self.box = QtGui.QVBoxLayout()
        self.box.addWidget(self.label)
        self.setLayout(self.box)
class MyWidgetBilling(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.tname = "Биллинг"
        self.label = QtGui.QLabel("")
        self.box = QtGui.QVBoxLayout()
        self.box.addWidget(self.label)
        self.setLayout(self.box)
        
class MyWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.mdi_area = QtGui.QMdiArea()
        self.setCentralWidget(self.mdi_area)
        self.add_menu()
        self._opened_windows = {}
        
    def add_menu(self):
        self.menuStat = QtGui.QMenu("&Первое меню")
        self.actKomand = QtGui.QAction("&Командировки", None)
        self.actKomand.triggered.connect(partial(self.on_window, MyWidgetKomand))
        self.menuStat.addAction(self.actKomand)
        self.menuBar().addMenu(self.menuStat)
        self.menuStat1 = QtGui.QMenu("&Второе меню")
        self.actBilling = QtGui.QAction("&Биллинг", None)
        self.actBilling.triggered.connect(partial(self.on_window, MyWidgetBilling))
        self.menuStat1.addAction(self.actBilling)
        self.menuBar().addMenu(self.menuStat1)
    def on_window(self, widget_type):
        subWindow = self._opened_windows.get(widget_type)
        if subWindow:
            self.mdi_area.setActiveSubWindow(subWindow)
            return
        widgetObject = widget_type()
        subWindow = self._opened_windows[widget_type] = self.mdi_area.addSubWindow(widgetObject)
        subWindow.resize(600, 250)
        #window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        subWindow.setWindowTitle(widgetObject.tname)
        subWindow.show()
app = QtGui.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle("")
window.resize(700, 350)
window.show()
sys.exit(app.exec_())

Я так понимаю, нужно чтоб в момент закрытия окна (window.setAttribute(QtCore.Qt.WA_DeleteOnClose)) из self._opened_windows удалялся этот объект. Или как?)
reclosedev
tiglon
Я так понимаю, нужно чтоб в момент закрытия окна (window.setAttribute(QtCore.Qt.WA_DeleteOnClose)) из self._opened_windows удалялся этот объект. Или как?)

Да, но это не очень удобно. Проще добавить проверку на присутствие subWindow в mdiArea:
subWindow = self._opened_windows.get(widget_type)
if subWindow and subWindow in self.mdi_area.subWindowList():
    ...
Тогда можно и
subWindow.setAttribute(QtCore.Qt.WA_DeleteOnClose)
оставить.

Пробовал еще с weakref.WeakValueDictionary(), но не получилось, так как добавление в mdiArea не означает, что ссылка будет сильной.

upd:
Кстати, вместо tname, в виджете можно заголовок ставить.
self.setWindowTitle("Командировки")
tiglon
Спасибо.

Да, это я чёт извернулся
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB