How to show another window - python

The project occurs loging in and signing in.
Im trying a transition from registerwindow to mainwindow and when we submit the window is automatically transit to mainwindow. There is only way to do this (at least for me) i have to import two python doc which named mainwindow.py and register.py, they are in same doc by the way.
This is the mainmenu.py
from PyQt5 import QtCore,QtGui,QtWidgets
from window.register import Ui_Form
class Ui_MainWindow(object):
def login(self):
self.window = QtWidgets.QWidget()
self.ui = Ui_Form()
self.ui.setupUi(self.window)
self.window.show()
MainWindow.hide()
and this is register.py
from PyQt5 import QtCore, QtGui, QtWidgets
from window.mainmenu import Ui_MainWindow
import sqlite3
class Ui_Form(object):
def submit(self):
sorgu2 = "Select * From users where nickname = ?"
sorgu = "INSERT INTO users values(?,?)"
self.cursor.execute(sorgu,(self.lineEdit.text(),self.lineEdit.text()))
self.connect.commit()
Form.hide()
self.window2 = QtWidgets.QMainWindow()
self.ui2 = Ui_MainWindow()
self.ui2.setupUi(self.window2)
self.window2.show()
Its supposed to be when i clicked to the button the register window will be hidden and mainmenu window will be show. Same thing for the mainmenu but the direct opposite
I know i am doing circular dependent imports but there is no other way but importing them to each other

If second window will be QDialog then you can hide main window, use exec() for QDialog and main window will wait till you close QDialog, and when it returns to main window then you can show it again.
from PyQt5 import QtWidgets
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.button = QtWidgets.QPushButton("Show Second Window", self)
self.button.clicked.connect(self.show_second_window)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.button)
self.show()
def show_second_window(self):
self.hide() # hide main window
self.second = SecondWindow()
self.second.exec() # will wait till you close second window
self.show() # show main window again
class SecondWindow(QtWidgets.QDialog): # it has to be dialog
def __init__(self):
super().__init__()
self.button = QtWidgets.QPushButton("Close It", self)
self.button.clicked.connect(self.show_second_window)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.button)
self.show()
def show_second_window(self):
self.close() # go back to main window
app = QtWidgets.QApplication([])
main = MainWindow()
app.exec()
The other popular method is to create two widgets with all contents and replace widgets in one window.
from PyQt5 import QtWidgets
class MainWidget(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.button = QtWidgets.QPushButton("Show Second Window", self)
self.button.clicked.connect(self.show_second_window)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.button)
self.show()
def show_second_window(self):
self.close()
self.parent.set_content("Second")
class SecondWidget(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.button = QtWidgets.QPushButton("Close It", self)
self.button.clicked.connect(self.show_second_window)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.button)
self.show()
def show_second_window(self):
self.close()
self.parent.set_content("Main")
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QVBoxLayout(self)
self.set_content("Main")
self.show()
def set_content(self, new_content):
if new_content == "Main":
self.content = MainWidget(self)
self.layout.addWidget(self.content)
elif new_content == "Second":
self.content = SecondWidget(self)
self.layout.addWidget(self.content)
app = QtWidgets.QApplication([])
main = MainWindow()
app.exec()
EDIT: Change window's content using QStackedLayout
from PyQt5 import QtWidgets
class FirstWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
layout = QtWidgets.QVBoxLayout(self)
self.button = QtWidgets.QPushButton("Show Second Stack", self)
self.button.clicked.connect(self.change_stack)
layout.addWidget(self.button)
def change_stack(self):
self.parent().stack.setCurrentIndex(1)
class SecondWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
layout = QtWidgets.QVBoxLayout(self)
self.button = QtWidgets.QPushButton("Show First Stack", self)
self.button.clicked.connect(self.change_stack)
layout.addWidget(self.button)
def change_stack(self):
self.parent().stack.setCurrentIndex(0)
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.stack = QtWidgets.QStackedLayout(self)
self.stack1 = FirstWidget(self)
self.stack2 = SecondWidget(self)
self.stack.addWidget(self.stack1)
self.stack.addWidget(self.stack2)
self.show()
app = QtWidgets.QApplication([])
main = MainWindow()
app.exec()

Related

Calling method from a second class to update QListView data

I have two tabs, Tab1, and Tab2. On Tab2, there is a button that when clicked, calls a method that updates the QListView data in the same tab. This works successfully.
When trying to call the same method from another class, it will not work. Below is a minimum reproducible example.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (
QDesktopWidget,
QVBoxLayout,
QHBoxLayout,
QPushButton,
)
from PyQt5.QtCore import Qt
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle('App')
self.resize(1200, 800)
self.center()
self.window = MainWindow(self)
self.setCentralWidget(self.window)
self.show()
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
class MainWindow(QtWidgets.QWidget):
def __init__(self, parent):
super(MainWindow, self).__init__(parent)
layout = QVBoxLayout(self)
# Initialize Tabs
tab_holder = QtWidgets.QTabWidget()
tab1 = Home()
tab2 = SecondTab()
tab_holder.addTab(tab1, "Tab1")
tab_holder.addTab(tab2, 'Tab2')
layout.addWidget(tab_holder)
class Home(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Home, self).__init__(parent)
lay = QVBoxLayout(self)
self.btn_login = QPushButton('Login')
self.btn_login.clicked.connect(self.login)
lay.addWidget(self.btn_login)
#QtCore.pyqtSlot()
def login(self):
print('Hello')
SecondTab.load_info()
class SecondTab(QtWidgets.QWidget):
def __init__(self, parent=None):
super(SecondTab, self).__init__(parent)
lay = QVBoxLayout(self)
# Choice Boxes
layout_choice_boxes = QHBoxLayout()
self.list_of_items = QtWidgets.QListView()
self.model_dist = QtGui.QStandardItemModel(self.list_of_items)
layout_choice_boxes.addWidget(self.list_of_items)
# Load data button.
self.loadData = QPushButton('Load Data')
self.loadData.clicked.connect(self.load_info)
# Add all components to main layout.
lay.addLayout(layout_choice_boxes)
lay.addWidget(self.loadData)
#QtCore.pyqtSlot()
def load_info(self):
for member in ['Item 1', 'Item 2', 'Item 3']:
item = QtGui.QStandardItem(member)
item.setCheckable(True)
item.setEditable(False)
check = Qt.Unchecked
item.setCheckState(check)
self.model_dist.appendRow(item)
self.list_of_items.setModel(self.model_dist)
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
The error is on the line in the class Home() where I try to call the method from the SecondTab() class: SecondTab.load_info()
The load_info() method uses self in the SecondTab class, so I tried passing in the class directly like this: SecondTab.load_info(SecondTab()), however, it did not work.
This is a problem about the basic OOP issues, you have to interact with the instances (the objects) and not the classes (the abstraction). So the solution is that the connection between the objects "tab1" and "tab2":
class MainWindow(QtWidgets.QWidget):
def __init__(self, parent):
super(MainWindow, self).__init__(parent)
layout = QVBoxLayout(self)
# Initialize Tabs
tab_holder = QtWidgets.QTabWidget()
tab1 = Home()
tab2 = SecondTab()
tab_holder.addTab(tab1, "Tab1")
tab_holder.addTab(tab2, 'Tab2')
layout.addWidget(tab_holder)
tab1.btn_login.clicked.connect(tab2.load_info)
class Home(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Home, self).__init__(parent)
lay = QVBoxLayout(self)
self.btn_login = QPushButton('Login')
lay.addWidget(self.btn_login)

I can't get window to resize when I hide a widget

I found some code on here that shows an example of how you can get the window to resize when the widget is hidden, and it works for me. Here is the code:
from PyQt4 import QtCore, QtGui
import sys
class MainWindow(QtGui.QWidget):
def __init__(self):
self.app = QtGui.QApplication(sys.argv)
super(MainWindow, self).__init__()
self.button = QtGui.QPushButton('Show/Hide')
self.button.setCheckable(True)
self.frame = QtGui.QFrame()
self.frame.setFixedHeight(100)
self.layout = layout = QtGui.QVBoxLayout()
layout2 = QtGui.QVBoxLayout()
self.setLayout(layout)
self.frame.setLayout(layout2)
layout.addWidget(self.button)
layout.addWidget(self.frame)
layout.addStretch(1)
layout2.addWidget(QtGui.QLabel('Yoyoyo'))
self.button.toggled.connect(self.clickAction)
def startup(self):
self.show()
sys.exit(self.app.exec_())
def clickAction(self):
checked = self.button.isChecked()
if checked:
self.frame.show()
else:
self.frame.hide()
QtCore.QTimer.singleShot(0, self.resizeMe)
def resizeMe(self):
self.resize(self.minimumSizeHint())
if __name__ == "__main__":
myApp = MainWindow()
myApp.startup()
I then tried to modify this to match my existing code by separating the mainWindow class and the widget class. Here is the code that does that.
from PySide import QtGui,QtCore
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.w = testW(self)
self.setCentralWidget(self.w)
self.show()
class testW(QtGui.QWidget):
def __init__(self,parent):
super(testW,self).__init__()
self.parent = parent
self.button = QtGui.QPushButton('Show/Hide')
self.button.setCheckable(True)
self.button.setChecked(True);
self.frame = QtGui.QFrame()
self.frame.setFixedHeight(100)
self.layout = layout = QtGui.QVBoxLayout()
layout2 = QtGui.QVBoxLayout()
self.setLayout(layout)
self.frame.setLayout(layout2)
layout.addWidget(self.button)
layout.addWidget(self.frame)
layout.addStretch(1)
layout2.addWidget(QtGui.QLabel('Yoyoyo'))
self.button.toggled.connect(self.clickAction)
def clickAction(self):
checked = self.button.isChecked()
if checked:
self.frame.show()
else:
self.frame.hide()
QtCore.QTimer.singleShot(0, self.resizeMe)
def resizeMe(self):
self.resize(self.minimumSizeHint())
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myApp = MainWindow()
sys.exit(app.exec_())
#time.sleep(1)
Running the first code does what I want it to. After I hide the widget, the window resizes to the correct size. The second implementation of the code does not shrink and expand the window when I hide and show the widget. Is this because the MainWindow is in a separate class?
Use size policies for your widgets. For your example you can change UI creation code as follows:
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.w = testW(self)
self.w.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
QtWidgets.QSizePolicy.MinimumExpanding
)
self.setCentralWidget(self.w)
self.show()
Please note new setSizePolicy call which say Qt layout engine how to change the size of your widget according to its content.
Unfortunately QMainWindow does not respect sizeHint automatically, but it is calculated properly, so you can adjustSize manually:
def clickAction(self):
checked = self.button.isChecked()
if checked:
self.frame.show()
else:
self.frame.hide()
QtCore.QTimer.singleShot(0, self.parent.adjustSize)
You do not need to resize your widget itself, because it will be resized according to the policy. Even sizeHint will be calculated automatically so you need only to call adjustSize of QMainWindow.
PS: I used PySide2 instead of PySide so the imports are different a little bit:
from PySide2 import QtWidgets, QtCore

PyQt5 passing argument between two classes: lambda vs partial

I am trying to pass an argument between two PyQt5 classes. I used three methods:
Using lambda functions.
Wrapper function (similar to lambda function).
partial from functools module.
In the example below, I have two windows:
MainWindow has QLineEdit mw_line_edit and a QPushButton mw_open_new_dialog_button.
Dialog: has a QLineEdit line_edit and aQPushButton push_button.
When I click the button push_button, I want it to insert the content of line_edit to mw_line_edit.
Here is a minimal example:
import sys
from functools import partial
from PyQt5 import QtWidgets, QtGui, QtCore
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.central_widget = QtWidgets.QWidget(self)
self.setCentralWidget(self.central_widget)
self.mw_open_new_dialog_button = QtWidgets.QPushButton('Open New dialog', self)
self.mw_line_edit = QtWidgets.QLineEdit(self)
self.hlayout = QtWidgets.QHBoxLayout(self)
self.hlayout.addWidget(self.mw_open_new_dialog_button)
self.hlayout.addWidget(self.mw_line_edit)
self.central_widget.setLayout(self.hlayout)
self.mw_open_new_dialog_button.clicked.connect(self.open_new_dialog)
def open_new_dialog(self):
self.dlg = Dialog()
#self.dlg.clicked.connect(partial(self.write_something, self.dlg.line_edit.text())) # <<<<<<< This does not work
self.dlg.clicked.connect(lambda: self.write_something(self.dlg.line_edit.text())) # this works
#self.dlg.clicked.connect(self.wrapper(self.dlg.line_edit.text()))# <<<<<<<<<<This does not work
self.dlg.exec()
#QtCore.pyqtSlot()
def write_something(self, text):
self.mw_line_edit.setText(text)
def wrapper(self, text):
return lambda: self.write_something(text)
class Dialog(QtWidgets.QDialog):
clicked = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(QtWidgets.QDialog, self).__init__(parent)
self.hlayout = QtWidgets.QHBoxLayout(self)
self.line_edit = QtWidgets.QLineEdit(self)
self.push_button = QtWidgets.QPushButton('Click me', self)
self.hlayout.addWidget(self.line_edit)
self.hlayout.addWidget(self.push_button)
self.label = QtWidgets.QLabel('I am a Qlabel', self)
self.hlayout.addWidget(self.label)
self.setLayout(self.hlayout)
self.push_button.clicked.connect(self.clicked)
def write_something(self, text):
print(text)
app = QtWidgets.QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec())
As you can see in the commented lines, only the following method works:
self.dlg.clicked.connect(lambda: self.write_something(self.dlg.line_edit.text()))
Why the other two do not work, i.e:
self.dlg.clicked.connect(partial(self.write_something, self.dlg.line_edit.text())) # <<<<<<< This does not work
self.dlg.clicked.connect(self.wrapper(self.dlg.line_edit.text()))# <<<<<<<<<<This does not work
Thanks
1) functools.partial()
What arguments are you passing to partial? You are passing the method write_something and the text of self.dlg.line_edit at the time the connection is made.
And what is the value of that text? it is an empty string, this explains the failure.
Is there any solution for this case? Yes, instead of passing the text, pass the QLineEdit, and in the method write_something get the text and set it in the other QLineEdit:
def open_new_dialog(self):
self.dlg = Dialog()
self.dlg.clicked.connect(partial(self.write_something, self.dlg.line_edit))
self.dlg.exec()
def write_something(self, le):
self.mw_line_edit.setText(le.text())
2) wrapper
It is the same problem, you are passing the empty text that you have at the moment of the connection
Is there any solution? Yes, the same solution as the previous one.
def open_new_dialog(self):
self.dlg = Dialog()
self.dlg.clicked.connect(self.wrapper(self.dlg.line_edit))
self.dlg.exec()
def write_something(self, text):
self.mw_line_edit.setText(text)
def wrapper(self, line):
return lambda: self.write_something(line.text())
Will there be a clean solution? Yes, create a signal that transports the text when you click.
from PyQt5 import QtWidgets, QtGui, QtCore
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
self.mw_open_new_dialog_button = QtWidgets.QPushButton('Open New dialog')
self.mw_line_edit = QtWidgets.QLineEdit()
hlayout = QtWidgets.QHBoxLayout(central_widget)
hlayout.addWidget(self.mw_open_new_dialog_button)
hlayout.addWidget(self.mw_line_edit)
self.mw_open_new_dialog_button.clicked.connect(self.open_new_dialog)
#QtCore.pyqtSlot()
def open_new_dialog(self):
self.dlg = Dialog()
self.dlg.textSignal.connect(self.mw_line_edit.setText)
self.dlg.exec()
class Dialog(QtWidgets.QDialog):
textSignal = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(QtWidgets.QDialog, self).__init__(parent)
hlayout = QtWidgets.QHBoxLayout(self)
self.line_edit = QtWidgets.QLineEdit()
self.push_button = QtWidgets.QPushButton('Click me')
hlayout.addWidget(self.line_edit)
hlayout.addWidget(self.push_button)
self.label = QtWidgets.QLabel('I am a Qlabel')
hlayout.addWidget(self.label)
self.push_button.clicked.connect(self.sendText)
#QtCore.pyqtSlot()
def sendText(self):
self.textSignal.emit(self.line_edit.text())
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec())

How do i open a class from within another class by selecting an item on ToolBar?? Python/PyQt

I am trying to run class AddTQuestions from a def in class AddTest but it wont work!! It opens the window AddTQuestions for a split-second then closes it straight away?!
The code is shown here:
import sys
from PyQt4 import QtCore, QtGui
class Example(QtGui.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
RunClassAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'Exit', self)
RunClassAction.triggered.connect(self.run)
self.toolbar = self.addToolBar('Exit')
self.toolbar.addAction(RunClassAction)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Why Wont this Woooorkkkkk')
self.show()
def run(self):
AddQuestion = AddTQuestions()
AddQuestion.show()
class AddTQuestions(QtGui.QMainWindow):
def __init__(self, parent=None):
super(AddTQuestions, self).__init__(parent)
self.welldone = QtGui.QLabel('WellDone')
self.button = QtGui.QPushButton('Press Me')
layout = QtGui.QVBoxLayout()
layout.addWidget(self.welldone)
layout.addWidget(self.button)
self.setLayout(layout)
print("hello")
if __name__ == '__main__':
app = QtGui.QApplication([])
window = Example()
window.show()
app.exec_()
The object get's garbage collected, since you don't hold any reference to it when the function ends.
add them as class variables like this and the window stays open.
self.AddQuestion = AddTQuestions()
self.AddQuestion.show()

PyQt: How to hide QMainWindow

Clicking Dialog_01's button hides its window and opens Dialog_02. Clicking Dialog_02's button should close its windows and unhide Dialog_01. How to achieve it?
import sys, os
from PyQt4 import QtCore, QtGui
class Dialog_02(QtGui.QMainWindow):
def __init__(self):
super(Dialog_02, self).__init__()
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
Button_02 = QtGui.QPushButton("Close THIS and Unhide Dialog 01")
Button_02.clicked.connect(self.closeAndReturn)
myBoxLayout.addWidget(Button_02)
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.setWindowTitle('Dialog 02')
def closeAndReturn(self):
self.close()
class Dialog_01(QtGui.QMainWindow):
def __init__(self):
super(Dialog_01, self).__init__()
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
Button_01 = QtGui.QPushButton("Hide THIS and Open Dialog 02")
Button_01.clicked.connect(self.callAnotherQMainWindow)
myBoxLayout.addWidget(Button_01)
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.setWindowTitle('Dialog 01')
def callAnotherQMainWindow(self):
self.hide()
self.dialog_02 = Dialog_02()
self.dialog_02.show()
self.dialog_02.raise_()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dialog_1 = Dialog_01()
dialog_1.show()
sys.exit(app.exec_())
Make the first window a parent of the second window:
class Dialog_02(QtGui.QMainWindow):
def __init__(self, parent):
super(Dialog_02, self).__init__(parent)
# ensure this window gets garbage-collected when closed
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
...
def closeAndReturn(self):
self.close()
self.parent().show()
class Dialog_01(QtGui.QMainWindow):
...
def callAnotherQMainWindow(self):
self.hide()
self.dialog_02 = Dialog_02(self)
self.dialog_02.show()
If you want the same dialog to be shown each time, do something like:
def callAnotherQMainWindow(self):
self.hide()
if not hassattr(self, 'dialog_02'):
self.dialog_02 = Dialog_02(self)
self.dialog_02.show()
and hide() the child window, rather than closing it.

Categories