I have been struggling with a problem recently and I cannot get around it. I have a PyQt QMainWindow which contains a subwindow :
As you can figure out, clicking on the GO! button will open a number of subwindows specified by the number in the QLineEdit :
And clicking on the QCheckBox inside each subwindow should display a text.
The problem is that this works only for the last spawned subwindow. The others appear to be inactive.
Is their a way to make them active?
Please find my code below:
from PyQt4 import QtGui
import mainWin
import subWin
import sys
class MainWindowGui():
def __init__(self):
self.w = QtGui.QMainWindow()
self.MainWindow = myWinCls(self)
self.MainWindow.setupUi(self.w)
self.w.showMaximized()
class myWinCls(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self)
self.parent = parent
def setupUi(self,Widget):
self.ui = mainWin.Ui_MainWindow()
self.ui.setupUi(Widget)
self.ui.mdiArea.addSubWindow(self.ui.subwindow)
self.ui.goBtn.clicked.connect(self.show_wins)
def show_wins(self):
N = int(self.ui.nbrEdit.text())
for self.k in xrange(N):
self.show_subwins()
def show_subwins(self):
self.win = QtGui.QWidget()
self.child_window = showSubWinCls(self)
self.child_window.setupUi(self.win)
self.subwin = self.ui.mdiArea.addSubWindow(self.win)
self.win.setWindowTitle("Subwin " + str(self.k))
self.subwin.show()
class showSubWinCls(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self)
self.parent = parent
def setupUi(self, Widget):
self.ui = subWin.Ui_Form()
self.ui.setupUi(Widget)
self.ui.checkBox.clicked.connect(self.show_msg)
def show_msg(self):
if self.ui.checkBox.isChecked():
self.ui.lineEdit.setText("Yiiiiiihaaaaaa !!!")
else:
self.ui.lineEdit.setText("")
def main():
app = QtGui.QApplication(sys.argv)
app.setStyle(QtGui.QStyleFactory.create('WindowsVista'))
ex = MainWindowGui()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I am sure this problem is somehow a classic trick but despite searching for some time now, I cannot figure it out.
Thanks for your help!
The problematic part:
def show_wins(self):
N = int(self.ui.nbrEdit.text())
for self.k in xrange(N):
self.show_subwins()
def show_subwins(self):
self.win = QtGui.QWidget()
self.child_window = showSubWinCls(self) #erase refererence to previous one
self.child_window.setupUi(self.win)
self.subwin = self.ui.mdiArea.addSubWindow(self.win)
self.win.setWindowTitle("Subwin " + str(self.k))
self.subwin.show()
You are only keeping reference to one subwindow in self.child_window, the last window openned.
In show_wins, you call show_subwin N time. Each time, you redefine self.child_window as a new instance of the class showSubWinCls. You lose the reference to the previous one.
You need to keep a reference to all the windows, otherwise signals and slots won't work. You can do something like this:
class myWinCls(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self)
self.parent = parent
self.subWindowList=[]
def show_subwins(self):
...
child_window = showSubWinCls(self)
child_window.setupUi(self.win)
self.subWindowList.append(child_window)
Related
Grееtings аll. I am new to this site, so go easy on me.
I am building a program in python using PyQt5 for the interface. I currently have, among other things, a QListWidget (list window) into which I insert a number of QWidgets (list items) through a function during the running of the program. I have implemented an eventFilter by subclassing QObject, and I use it to differentiate between left and right click, and from that I send to the controller class to handle one or the other click accordingly.
I have made it so that when right-clicked on a list item, a context menu appears. However, I also need a context menu to appear when the list window is clicked (not on a list item). The problem which occurs is that when right-clicked on a list item, both the list item context menu and list window context menu appear. This must be because the event filter recognises the click as occurring within the list window, because it is occurring on a list item, which is within the list window. What I need is that when right-clicked on a list item, only its context menu appears, and similarly for the list window, when right-clicked outside the list items.
I have tried checking if source equals the widget where the event appeared, but it seems to recognise both widgets' events independently and if I gate the call to the handler with an if condition, one of the handlers never receives a call. I have searched around the web and this site, but I have found nothing of use. Perhaps it is due to me not being a native speaker and so not being able to phrase things correctly (you can see how clunky my phrasing is).
Below follows some code extracted from my program. Note that anything irrelevant has been cut away to make for a minimal example. For your convenience, I have also merged the GUI files into one and did the same for the control files. I have tested this minimal example and it reproduces the problem. It could not get smaller, so if you deem the code listed below too long, notify me and I can reupload it to GitHub if it is allowed to show the minimal example that way instead of putting code into the question directly.
custom_classes.py:
from PyQt5.QtCore import Qt, QEvent, QObject
class MyFilter(QObject):
def __init__(self, parent, ctrl):
super().__init__(parent)
self._parent = parent
self.ctrl = ctrl
self.parent.installEventFilter(self)
#property
def parent(self):
return self._parent
def eventFilter(self, source, event):
if event.type() == QEvent.MouseButtonPress:
if event.button() == Qt.LeftButton:
self.ctrl.handle_left_click()
elif event.button() == Qt.RightButton:
self.ctrl.handle_right_click(event)
return super().eventFilter(source, event)
gui.py:
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QListWidget
from PyQt5.QtWidgets import QScrollArea
from PyQt5.QtCore import Qt
class MainFrame(QWidget):
def __init__(self):
super().__init__()
self.main_layout = QHBoxLayout()
self.setLayout(self.main_layout)
class ListItemFrame(QWidget):
def __init__(self):
super().__init__()
self.main = QHBoxLayout()
self.main.setContentsMargins(0,0,0,0)
self.name_layout = QHBoxLayout()
self.name_layout.setContentsMargins(0,0,0,0)
self.main.addLayout(self.name_layout)
self.name = QLabel("")
self.name.setMaximumHeight(20)
self.name_layout.addWidget(self.name)
self.setLayout(self.main)
class ListFrame(QListWidget):
def __init__(self):
super().__init__()
self.main = QVBoxLayout()
self.scroll_widget = QScrollArea()
self.scroll_widget.setWidgetResizable(True)
self.scroll_layout = QVBoxLayout()
self.scroll_layout.setAlignment(Qt.AlignTop)
self.scroll_layout_widget = QWidget()
self.scroll_layout_widget.setLayout(self.scroll_layout)
self.scroll_widget.setWidget(self.scroll_layout_widget)
self.main.addWidget(self.scroll_widget)
self.setLayout(self.main)
ctrl.py:
from PyQt5.QtWidgets import QMenu
from gui import ListFrame, ListItemFrame
from custom_classes import MyFilter
class Controller:
def __init__(self, ui, app):
self.ui = ui
self.app = app
self.list_ = ListControl(self)
class ListControl:
def __init__(self, ctrl):
self.ctrl = ctrl
self.ui = ListFrame()
self.the_list = self.get_list() #list of stuff
self.item_list = [] #list of list items
self.ctrl.ui.main_page.main_layout.addWidget(self.ui)
self.index = self.ctrl.ui.main_page.main_layout.count() - 1
self.filter = MyFilter(self.ui, self)
self.show_list()
def handle_left_click(self):
pass #other irrelevant function
def handle_right_click(self, event):
self.show_options(event)
def show_options(self, event):
menu = QMenu()
one_action = menu.addAction("Something!")
quit_action = menu.addAction("Quit")
action = menu.exec_(self.ui.mapToGlobal(event.pos()))
if action == quit_action:
self.ctrl.ui.close()
elif action == one_action:
self.something()
def something(self):
print("Something!")
def show_list(self):
for info in self.the_list:
item = ListItem(self, info)
self.item_list.append(item)
def get_list(self):
return [x for x in "qwertzuiopasdfghjklyxcvbnm"]
class ListItem:
def __init__(self, main, info):
self.main = main
self.info = info*10
self.ui = ListItemFrame()
self.filter = MyFilter(self.ui, self)
self.set_ui()
self.add_to_ui()
self.main.ui.scroll_layout.addWidget(self.ui)
def handle_left_click(self):
pass #other irrelevant function
def handle_right_click(self, event):
self.show_options(event)
def show_options(self, event):
menu = QMenu()
item_action = menu.addAction("Hello!")
quit_action = menu.addAction("Quit")
action = menu.exec_(self.ui.mapToGlobal(event.pos()))
if action == quit_action:
self.main.ctrl.ui.close()
elif action == item_action:
self.hello()
def hello(self):
print(f"Hello! I am {self.info}")
def set_ui(self):
self.ui.name.setText(self.info)
def add_to_ui(self):
self.main.ui.scroll_layout.insertWidget(
self.main.ui.scroll_layout.count() - 1, self.ui
)
main.py:
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QStackedLayout
from PyQt5.QtWidgets import QWidget
from gui import MainFrame
from ctrl import Controller
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("minimal example")
self.stacked = QStackedLayout()
self.main_page = MainFrame()
self.stacked.addWidget(self.main_page)
self.setLayout(self.stacked)
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setStyle("Fusion")
window = Window()
window.show()
c = Controller(window, app)
sys.exit(app.exec())
To reiterate, the context menu appears for both the list item and the list window when a list item is right-clicked. What I need is for it to appear only for the list item if a list item is right-clicked.
Edit: seems the site bit off a part of my introduction. Readded it!
this is probably not the best way to do it but it works. You just create a global variable, for example list_element_clicked and when you click "hello" (of course not quit because you are going to exit the window and there is no point) you set that variable to True. If that variable is False, you show the ListControl context menu, and if not, you set that variable to True, so next time if you click on your ListControl it will appear, and if you click on ListItem it will not.
Finally there is an extra case, if you don't click anywhere after clicking on ListItem, nothing will happen (the ListControl is not shown and the variable is not changed) so everything will work perfectly next time.
So here is the code:
ctrl.py:
from PyQt5.QtWidgets import QMenu
from gui import ListFrame, ListItemFrame
from custom_classes import MyFilter
list_element_clicked = False
class Controller:
def __init__(self, ui, app):
self.ui = ui
self.app = app
self.list_ = ListControl(self)
class ListControl:
def __init__(self, ctrl):
self.ctrl = ctrl
self.ui = ListFrame()
self.the_list = self.get_list() #list of stuff
self.item_list = [] #list of list items
self.ctrl.ui.main_page.main_layout.addWidget(self.ui)
self.index = self.ctrl.ui.main_page.main_layout.count() - 1
self.filter = MyFilter(self.ui, self)
self.show_list()
def handle_left_click(self):
pass #other irrelevant function
def handle_right_click(self, event):
global list_element_clicked
if(list_element_clicked == False):
self.show_options(event)
else:
list_element_clicked = False
def show_options(self, event):
menu = QMenu()
one_action = menu.addAction("Something!")
quit_action = menu.addAction("Quit")
action = menu.exec_(self.ui.mapToGlobal(event.pos()))
if action == quit_action:
self.ctrl.ui.close()
elif action == one_action:
self.something()
def something(self):
print("Something!")
def show_list(self):
for info in self.the_list:
item = ListItem(self, info)
self.item_list.append(item)
def get_list(self):
return [x for x in "qwertzuiopasdfghjklyxcvbnm"]
class ListItem:
def __init__(self, main, info):
self.main = main
self.info = info*10
self.ui = ListItemFrame()
self.filter = MyFilter(self.ui, self)
self.set_ui()
self.add_to_ui()
self.main.ui.scroll_layout.addWidget(self.ui)
def handle_left_click(self):
pass #other irrelevant function
def handle_right_click(self, event):
self.show_options(event)
def show_options(self, event):
menu = QMenu()
item_action = menu.addAction("Hello!")
quit_action = menu.addAction("Quit")
action = menu.exec_(self.ui.mapToGlobal(event.pos()))
if action == quit_action:
self.main.ctrl.ui.close()
elif action == item_action:
global list_element_clicked
list_element_clicked = True
self.hello()
def hello(self):
print(f"Hello! I am {self.info}")
def set_ui(self):
self.ui.name.setText(self.info)
def add_to_ui(self):
self.main.ui.scroll_layout.insertWidget(
self.main.ui.scroll_layout.count() - 1, self.ui
)
I have a QToolTip on a QLineEdit and the tooltip contains variables in the text. The tooltip code is contained in the init. The problem is that the variable values in the tooltip do not update automatically when they are changed in the operation of the program. For example, I hover over the line edit and values appear in the tooltip. I change the program, go back to the line edit, and variables in the tooltip have not changed.
I can fix the issue by moving the .setToolTip to a function and calling the function EACH time ANYTHING is changed in the program, but that seems like overkill, especially when 99% of the program changes have nothing to do with this particular tooltip).
Are variables supposed to update automatically? Here is the tooltip setup code contained in the init.
self.ui.YourSSAmount.setToolTip(
'<span>Click Reports/Social Security to see your<br>SS income at each start age'
'<br><br>Your inf adj FRA amt at age {}: ${:,.0f}'
'<br>Age adjustment: {:.0f}%'
'<br>SS Income at age {}: ${:,.0f}</span>'.format(
self.generator.YouSSStartAge, self.generator.your_new_FRA_amt,
self.generator.SS66.get(self.generator.YouSSStartAge, 1.32) * 100, self.generator.YouSSStartAge,
self.generator.YourSSAmount))
The setToolTip method takes the text and stores it, and is not notified if any of the variables used to form the text change.
Given this there are 2 possible solutions:
Update the tooltip every time a variable changes:
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.le = QtWidgets.QLineEdit()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.le)
self.foo = QtCore.QDateTime.currentDateTime().toString()
self.update_tooltip()
timer = QtCore.QTimer(self, timeout=self.on_timeout)
timer.start()
def on_timeout(self):
self.foo = QtCore.QDateTime.currentDateTime().toString()
# every time any variable used to build the tooltip changes
# then the text of the tooltip must be updated
self.update_tooltip()
def update_tooltip(self):
# update tooltip text
self.setToolTip("dt: {}".format(self.foo))
if __name__ == "__main__":
app = QtWidgets.QApplication([])
w = Widget()
w.show()
app.exec_()
Override the toolTip to take the text using the variables:
from PyQt5 import QtCore, QtWidgets
class LineEdit(QtWidgets.QLineEdit):
def __init__(self, parent=None):
super().__init__(parent)
self._foo = ""
#property
def foo(self):
return self._foo
#foo.setter
def foo(self, foo):
self._foo = foo
def event(self, e):
if e.type() == QtCore.QEvent.ToolTip:
text = "dt:{}".format(self.foo)
QtWidgets.QToolTip.showText(e.globalPos(), text, self, QtCore.QRect(), -1)
e.accept()
return True
return super().event(e)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.le = LineEdit()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.le)
self.le.foo = QtCore.QDateTime.currentDateTime().toString()
timer = QtCore.QTimer(self, timeout=self.on_timeout)
timer.start()
def on_timeout(self):
self.le.foo = QtCore.QDateTime.currentDateTime().toString()
if __name__ == "__main__":
app = QtWidgets.QApplication([])
w = Widget()
w.show()
app.exec_()
How does one use a QFileSystemModel to populate several QComboBox with subdirectories?
I have built a project management tool that allows me to create and manage my projects. I am currently using a combination of os.listdir and json to populate and validate my QComboboxes. But I am trying to learn a more modelview approach with QFileSystemModel.
So this is what I have:
class FileSystemModel(QW.QFileSystemModel):
def __init__(self, root, parent=None):
QW.QFileSystemModel.__init__(self, parent)
self.root = root
self.rootIndex = self.setRootPath(root)
class Window(QW.QWidget):
def __init__(self, parent=None):
super(Window, self).__init__()
self.init()
def init(self):
layout = QW.QVBoxLayout()
self.cbox = QW.QComboBox()
self.cbox2 = QW.QComboBox()
self.model = FileSystemModel("C:\\projects\\")
self.cbox.setModel(self.model)
self.cbox2.setModel(self.model)
self.cbox.setRootModelIndex(self.model.rootIndex)
self.cbox.currentIndexChanged.connect(self._indexChanged)
layout.addWidget(self.cbox)
layout.addWidget(self.cbox2)
self.setLayout(layout)
def _indexChanged(self):
row = self.sender().currentIndex()
index = self.sender().rootModelIndex().child(row, 0)
self.cbox2.setRootModelIndex(index)
def main():
app = QW.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
I was attempting to repopulate the cbox2 using the index from cbox, but with my code it doesn't seem to work - it just stays empty.
Okay here is modified version of what you had:
from sys import exit as sysExit
from PyQt5.QtCore import QDir, pyqtSlot
from PyQt5.QtWidgets import QApplication, QWidget, QFileSystemModel, QHBoxLayout, QComboBox
class SysDirModel(QFileSystemModel):
def __init__(self, DirPath):
QFileSystemModel.__init__(self)
self.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)
self.setReadOnly(True)
# Property
self.setRootPath(DirPath)
# Property
self.RootIndex = self.index(DirPath)
class SysFileModel(QFileSystemModel):
def __init__(self, DirPath):
QFileSystemModel.__init__(self)
self.setFilter(QDir.NoDotAndDotDot | QDir.Files)
self.setReadOnly(True)
# Property
self.setRootPath(DirPath)
# Property
self.RootIndex = self.index(DirPath)
def ResetPath(self, DirPath):
self.setRootPath(DirPath)
self.RootIndex = self.index(DirPath)
class MainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setGeometry(150, 150, 450, 100)
# If you use forward slash this works in Windows as well and it is cleaner
self.SysDirs = SysDirModel('C:/projects/')
self.SysFils = SysFileModel('C:/projects/')
# Setup first ComboBox
self.cbxDirs = QComboBox()
self.cbxDirs.setMinimumWidth(200)
self.cbxDirs.setModel(self.SysDirs)
self.cbxDirs.setRootModelIndex(self.SysDirs.RootIndex)
# This sends a Signal to a predefined Slot
self.cbxDirs.currentIndexChanged.connect(self.IndexChanged)
self.cbxFiles = QComboBox()
self.cbxFiles.setMinimumWidth(200)
self.cbxFiles.setModel(self.SysFils)
self.cbxFiles.setRootModelIndex(self.SysFils.RootIndex)
HBox = QHBoxLayout()
HBox.addWidget(self.cbxDirs)
HBox.addStretch(1)
HBox.addWidget(self.cbxFiles)
self.setLayout(HBox)
# This is the receiver of a Signal (aka Slot) so it ought to be used as such
#pyqtSlot(int)
def IndexChanged(self, RowIdx):
# Get your Current DirPath based on the Selected Value
index = self.cbxDirs.rootModelIndex().child(RowIdx, 0)
DirPath = self.cbxDirs.model().filePath(index)
# Reset what ComboBox 2's Model and what it is looking at
self.cbxFiles.clear()
self.SysFils.ResetPath(DirPath)
self.cbxFiles.setModel(self.SysFils)
if __name__ == '__main__':
MainThred = QApplication([])
MainGui = MainWindow()
MainGui.show()
sysExit(MainThred.exec_())
I have 2 QListWidget list objects, first one contain some data before showing off main GUI, second one is filling with another data when something has been selected from the first list... I'm trying to fill the second list with 1 million items using multi-threading to not freeze the main GUI windows while that task is in process.
self.lst1= QtGui.QListWidget(self.groupBox)
self.lst2= QtGui.QListWidget(self.groupBox)
self.lst1.itemSelectionChanged.connect(lambda: self.thread_list_filler(idx = 0))
def thread_list_filler(self, idx):
if idx == 0:
th = Thread(target = self.fill_List2)
th.start()
def fill_List2(self):
self.lst2.clear()
for i in range(1,1000000+1):
self.lst2.addItem(str(i))
The GUI is crashing every time when i press some item from lst1, whats the problem and how to avoid this?
You're not supposed to interact with gui elements outside the main thread. I.e. you should emit a signal in the thread, and connect this signal to a slot which will do the actual adding-to-list business.
Note however that 1 million items is a HUGE amout of data to put in a QListWidget.
Anyway, something like that may work:
class MyWidget(QtGui.QWidget):
addRequested = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
layout = QtGui.QVBoxLayout(self)
self.groupBox = QtGui.QGroupBox('Test', self)
layout.addWidget(self.groupBox)
vlayout = QtGui.QVBoxLayout(self.groupBox)
self.button = QtGui.QPushButton("Fill it", self.groupBox)
self.lst2 = QtGui.QListWidget(self.groupBox)
vlayout.addWidget(self.button)
vlayout.addWidget(self.lst2)
self.button.clicked.connect(self.thread_list_filler)
self.addRequested.connect(self.lst2.addItem)
def thread_list_filler(self):
self.lst2.clear()
th = threading.Thread(target = self.fill_List2)
th.start()
def fill_List2(self):
for i in range(1,1000000+1):
self.addRequested.emit(str(i))
Even though it's been awhile since i asked this question, here is a solution for it which suits my problem very well.
from PyQt4 import QtGui, QtCore
from qTest import Ui_Form
import sys
from time import sleep
class WorkerThread(QtCore.QThread):
def __init__(self, parent):
super(WorkerThread, self).__init__(parent)
self.stopFlag = False
def run(self):
for i in xrange(0, 1000000):
if self.stopFlag:
break
self.emit(QtCore.SIGNAL('addIntoList(int)'), i)
sleep(0.001)
self.stopFlag = False
def stop(self):
self.stopFlag = True
class TEST(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.stopThread)
self.ui.pushButton_2.clicked.connect(self.close)
self.lst1 = self.ui.listWidget_1
self.lst2 = self.ui.listWidget_2
self.qThread = WorkerThread(self)
self.connect(self.qThread, QtCore.SIGNAL("addIntoList(int)"), self.addIntoList)
for i in range(10):
self.lst1.addItem("%d" % i)
self.lst1.currentRowChanged.connect(self.thread_list_filler)
#QtCore.pyqtSlot(int)
def addIntoList(self, item):
self.lst2.addItem(str(item))
def stopThread(self):
self.qThread.stop()
def thread_list_filler(self, row):
if self.qThread.isRunning():
self.qThread.stop()
self.qThread.wait()
self.lst2.clear()
if row == 0:
self.qThread.start()
QtGui.QApplication.setStyle('cleanlooks')
font = QtGui.QFont()
font.setPointSize(10)
font.setFamily('Arial')
app = QtGui.QApplication(sys.argv)
app.setAttribute(QtCore.Qt.AA_DontShowIconsInMenus,False)
app.setFont(font)
window = TEST()
window.show()
sys.exit(app.exec_())
I made the simple code below as example. It justs open a new window clicking on a button. I don't find a way to prevent this widget to be re-opened if it is already on the screen. I would like to open a QDialog warning if the window already exists and mainly to have the closeEvent method sending a signal to Mainwidget saying that the new window has been closed. This would allow to open the newWidget again.
import sys
from PyQt4 import QtCore, QtGui
class NewWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(NewWidget,self).__init__(parent)
self.lineEdit = QtGui.QLineEdit('new window',self)
self.resize(200,50)
self.show()
def closeEvent(self,ev):
self.Exit = QtGui.QMessageBox.question(self,
"Confirm Exit...",
"Are you sure you want to exit ?",
QtGui.QMessageBox.Yes| QtGui.QMessageBox.No)
ev.ignore()
if self.Exit == QtGui.QMessageBox.Yes:
ev.accept()
class MainWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWidget,self).__init__(parent)
self.button = QtGui.QPushButton("button", self)
self.button.clicked.connect(self.open_new)
def open_new(self):
self.new = NewWidget()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main = MainWidget()
main.resize(200,50)
main.move(app.desktop().screen().rect().center() - main.rect().center())
main.show()
sys.exit(app.exec_())
I think a better solution is to avoid creating a new window every time you click the button.
One way to do this would be to change the subwindow to a QDialog:
class NewWidget(QtGui.QDialog):
...
and move the resize/show lines into the open_new method:
class MainWidget(QtGui.QWidget):
def __init__(self, parent=None):
...
self._subwindow = None
def open_new(self):
if self._subwindow is None:
self._subwindow = NewWidget(self)
self._subwindow.resize(200, 50)
# move it next to the main window
pos = self.frameGeometry().topLeft()
self._subwindow.move(pos.x() - 250, pos.y())
self._subwindow.show()
self._subwindow.activateWindow()
So now there is only ever one subwindow, which just gets re-activated whenever the button is clicked.
Great. The final solution of my problem looks like this :
class MainWidget(QtGui.QWidget):
def __init__(self, parent=None):
...
self._subwindow = QtGui.Qdialog()
def open_new(self):
if self.subwindow.isVisible() is False:
self._subwindow = NewWidget(self)
self._subwindow.resize(200, 50)
# move it next to the main window
pos = self.frameGeometry().topLeft()
self._subwindow.move(pos.x() - 250, pos.y())
self._subwindow.show()
self._subwindow.activateWindow()