I successfully created a second window (ChiffrerWindow) but whenever I try to click a button in the second window nothing happens (The button don't execute the slots). They behave like blank widgets
I have 5 files ui_mainwindow.py and ui_chiffrerwindow.py (Which are generated from QtDesigner), chiffrerwindow.py and mainwindow.py (Are the corresponding files where I pass in the slots),
main.py (Executes the app).
This is my mainwindow.py (I didn't show the top file imports)
from ui_mainwindow import Ui_MainWindow
from ui_chiffrerwindow import Ui_ChiffrerWindow
class MainWindow(QMainWindow, Ui_MainWindow,Ui_ChiffrerWindow):
def __init__(self,app):
super().__init__()
self.setupUi(self)
self.actionChiffrer.triggered.connect(self.ouvrirChiffrer)
def ouvrirChiffrer(self):
self.window = QtWidgets.QMainWindow()
self.ui = Ui_ChiffrerWindow()
self.ui.setupUi(self.window)
self.window.show()
This is my chiffrerwindow.py
from ui_chiffrerwindow import Ui_ChiffrerWindow
class ChiffrerWindow(QMainWindow, Ui_ChiffrerWindow):
def __init__(self,app):
super().__init__()
self.setupUi(self)
self.ui = Ui_ChiffrerWindow()
# self.getFileToEncrypt = self.findChild(QPushButton, "pushButtonFileDirCrypt")
# self.getPubKeyToEncrypt = self.findChild(QPushButton, "pushButtonPubKeyCrypt")
# self.line_edit_file_dir = self.findChild(QLineEdit, "lineEditFileDirCrypt")
# self.ine_edit_pub_key = self.findChild(QLineEdit, "lineEditPubKeyCrypt")
self.ui.pushButtonFileDirCrypt.clicked.connect(self.getFileToEncrypt)
self.ui.pushButtonPubKeyCrypt.clicked.connect(self.getPubKeyToEncrypt)
def getFileToEncrypt(self):
fname = QFileDialog.getOpenFileName(self,"Open File","", "All Files (*);; Word Documents (*.docx)")
# Output file name
if fname:
self.ui.lineEditFileDirCrypt.setText(fname[0])
def getPubKeyToEncrypt(self):
print("You want to get the keys to encrypt the file")
This is what my app looks like. This is the main window
This is the main window
This is the second window
This is the second window. Whenever I click the buttons on the second window I would like to open a File Dialog to permit to the user to select a file.
I am a beginner and this is a project of implementing PGP cryptography in a desktop app.
Thank you very much for your concern and your help
Related
I have been building an application in Python 3.10 and PyQt6. This application has 3 parts: A main window that has a grid of buttons, a settings window that settings which change depending on the button clicked, and a window where a task is run using those settings.
The application works 100% in PyCharm. When packaged using PyInstaller 5.0.1, the main and settings windows load fine. In the settings, I have a button to launch a QFileDialog so the user can select a directory. However, for half of the settings windows, when the user either hits "Cancel" or selects a directory, the entire program crashes. For the other half, everything works as intended (the selected directory is stored as a string). The specific windows that fail or don't never change.
The function to open the QFileDialog, the button to launch that function, and the class variable where the string is store are all part of the parent class. I have included a snippet below that has my general structure: A settings class (which is in settings.py) and two children of that class, DdSettings and PdSettings, which inherit from it (and are in discount.py). All of the code is public on my GitHub too.
class Settings(QWidget):
def __init__(self, task):
super().__init__()
# Window title
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
# setting the geometry of window
self.setGeometry(0, 0, 700, 400)
# Default directory
self.wd = 'No directory selected'
# Make overarching layout
self.over_layout = QVBoxLayout()
# Make a label with instructions
self.header = QLabel('Enter the appropriate values:', self)
self.header.setFont(QFont('Helvetica', 30))
self.header.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Add header to overarching layout
self.over_layout.addWidget(self.header)
# Make form layout for all the settingsguis
self.layout = QFormLayout()
# ID
self.idform = QLineEdit()
self.idform.setText('9999')
self.layout.addRow(QLabel('Subject ID:'), self.idform)
# Session form
self.sessionin = QLineEdit()
self.sessionin.setText('Pretest')
self.layout.addRow(QLabel('Session name/number (enter \"Practice\" to not have output):'), self.sessionin)
# WD input
self.wdset = QPushButton('Select Directory')
self.wdset.clicked.connect(self.fileselect)
self.wdlabel = QLabel(self.wd)
# Submit button
self.submit = QPushButton('Submit')
self.submit.clicked.connect(self.checksettings)
# Quit button
self.quitbutton = QPushButton('Quit')
self.quitbutton.clicked.connect(QApplication.instance().quit)
self.quitbutton.resize(self.quitbutton.sizeHint())
# Add in elements
self.elements()
# Show all elements
self.show()
def fileselect(self):
"""
This function creates a dialog window to select a directory that will be the output directoty and then sets
the class variable (and associated QLabel) for the working directory to the directory you chose
"""
folder = QFileDialog.getExistingDirectory(self, 'Select Directory')
self.wd = str(folder)
self.wdlabel.setText(self.wd)
# This works
class DdSettings(settings.Settings):
def __init__(self, task):
super().__init__(task)
def elements(self):
# Make form layout for all the settingsguis
self.layout.addRow(QLabel('Current output directory:'), self.wdlabel)
self.layout.addRow(QLabel('Click to choose where to save your output:'), self.wdset)
self.layout.addRow(self.quitbutton, self.submit)
# Add form layout to overarching layout
self.over_layout.addLayout(self.layout)
self.setLayout(self.over_layout)
# This does not work
class PdSettings(settings.Settings):
def __init__(self, task):
super().__init__(task)
def elements(self):
self.layout.addRow(QLabel('Current output directory:'), self.wdlabel)
self.layout.addRow(QLabel('Click to choose where to save your output:'), self.wdset)
self.layout.addRow(self.quitbutton, self.submit)
# Add form layout to overarching layout
self.over_layout.addLayout(self.layout)
self.setLayout(self.over_layout)
Nothing is changed from the parent, and this only crashes when the application is packaged. No error messages are thrown when I run the executable in the console window, so I have no idea how I can provide error messages for insight.
I have a main dialog window as shown below
Once the OK button is clicked, second window will open as shown below
I need to trigger the click event of login button frpm the second window. Below is my code. but i doesnt trigger any method.
from .gisedify_support_dialog_login import Ui_Dialog
FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'gisedify_support_dialog_base.ui'))
class GisedifySupportDialog(QtWidgets.QDialog, FORM_CLASS):
def __init__(self, parent=None):
"""Constructor."""
super(GisedifySupportDialog, self).__init__(parent)
# Set up the user interface from Designer through FORM_CLASS.
# After self.setupUi() you can access any designer object by doing
# self.<objectname>, and you can use autoconnect slots - see
# http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
# #widgets-and-dialogs-with-auto-connect
self.setupUi(self)
def open_login_dialog(self):
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.exec_()
ui.login_button.clicked.connect(self.login)
def login(self):
print('success')
class Login_Dialog(QtWidgets.QDialog,Ui_Dialog):
def __init__(self, parent=None):
super(Login_Dialog, self).__init__(parent)
QDialog.exec_() will block until the dialog is closed by the user so you would need to set up any signal-slot connections before you call Dialog.exec_(). When a dialog is closed, it returns 1 when de dialog was accepted, and 0 if not. Closing the dialog does not detroy it (unless you set a flag to do so), so you can retrieve the data that was entered after Dialog.exec_() returns.
So, instead of connecting a slot to the dialog button buttonin the main window, you could instead subclass QDialog, setup the ui using your Qt Designer files, and connect the button.clicked signal to the QDialog.accept slot. Then in the main widget you can call Dialog.exec_() as before and retrieve the information afterwards, e.g.
from PyQt5 import QtWidgets, QtCore, QtGui
class Login_Dialog(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent = None):
super().__init__(parent)
self.setupUi(self)
self.login_button.clicked.connect(self.accept)
class Widget(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__(parent)
# setup ui as before
def get_login(self):
dialog = Login_Dialog(self)
if dialog.exec_():
# get activation key from dialog
# (I'm assuming here that the line edit in your dialog is assigned to dialog.line_edit)
self.activation_key = dialog.line_edit.text()
self.login()
def login(self)
print(f'The activation_key you entered is {self.activation_key}')
I need to generate a custom popup input window triggered by clicking a QPushButton in my app (via clicked). It needs to get several inputs from the user of different types and then return them to the calling function inside the main window app. I have found built in functions such as QInputDialog that can do this for single specific inputs, but I can't figure out how to do this in the case of a popup that asks for several inputs of different types at once (preferably in a window designed in Qt Designer). Does anyone know how to do this?
import sys
import os
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5 import uic
path = os.path.dirname(__file__) #uic paths from itself, not the active dir, so path needed
qtCreatorFile = "NAME.ui" #Ui file name, from QtDesigner
Ui_MainWindow, QtBaseClass = uic.loadUiType(path + qtCreatorFile) #process through pyuic
class MyApp(QMainWindow, Ui_MainWindow): #gui class
def __init__(self):
#Set up the gui via Qt
super(MyApp, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.add_button.clicked.connect(self.add_row) #add_button is QPushButton
def add_row(self):
data1, data2, data3 = #popup form to get data (types are not the same)
#do stuff with data
pass
#start app
if __name__ == "__main__":
app = QApplication(sys.argv) #instantiate a QtGui (holder for the app)
window = MyApp()
window.show()
sys.exit(app.exec_())
There is no single solution but I will give you a guide to do what you want.
If you want to get a widget with the behavior of QInputDialog you must first choose the right template, in this case a good option is Dialog with Buttons Bottom or Dialog with Buttons Right, add the components you want, position it, etc.
Then as you show your code you create a class that inherits from QDialog and then create a method where you get the results but to do so do not use show() but exec_()
path = os.path.dirname(__file__)
qtCreatorFile = "some_dialog.ui"
Ui_Dialog, _ = uic.loadUiType(os.path.join(path,qtCreatorFile))
class CustomDialog(QDialog, Ui_Dialog):
def __init__(self):
super(CustomDialog, self).__init__()
self.setupUi(self)
# set initials values to widgets
def getResults(self):
if self.exec_() == QDialog.Accepted:
# get all values
val = self.some_widget.some_function()
val2 = self.some_widget2.some_another_function()
return val1, val2, ...
else:
return None
And then use it in your function:
class MyApp(QMainWindow, Ui_MainWindow): #gui class
def __init__(self):
#Set up the gui via Qt
super(MyApp, self).__init__()
self.setupUi(self)
self.add_button.clicked.connect(self.add_row) #add_button is QPushButton
def add_row(self):
w = CustomDialog()
values = w.getResults()
if values:
data1, data2, data3 = values
I have an application which has a main window, which can have multiple subwindows. I would like to have one set of QActions in the main window that interact with the currently selected window. For example, the application might be a text editor, and clicking file->save should save the text file the user is currently working on. Additionally, some QActions are checkable, so their checked state should reflect the state of the currently active window.
Here is a minimum working example that has the basic functionality I want, but I suspect there is a better way to do it (further discussion below the code).
import sys
import PyQt4.QtGui as QtGui
class DisplayWindow(QtGui.QWidget):
def __init__(self, parent=None, name="Main Window"):
# run the initializer of the class inherited from
super(DisplayWindow, self).__init__()
self.myLayout = QtGui.QFormLayout()
self.FooLabel = QtGui.QLabel(self)
self.FooLabel.setText(name)
self.myLayout.addWidget(self.FooLabel)
self.setLayout(self.myLayout)
self.is_foo = False
def toggle_foo(self):
self.is_foo = not self.is_foo
if self.is_foo:
self.FooLabel.setText('foo')
else:
self.FooLabel.setText('bar')
class WindowActionMain(QtGui.QMainWindow):
def __init__(self):
super(WindowActionMain, self).__init__()
self.fooAction = QtGui.QAction('Foo', self)
self.fooAction.triggered.connect(self.set_foo)
self.fooAction.setCheckable(True)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(self.fooAction)
self.toolbar = self.addToolBar('File')
self.toolbar.addAction(self.fooAction)
self.centralZone = QtGui.QMdiArea()
self.centralZone.subWindowActivated.connect(
self.update_current_window)
self.setCentralWidget(self.centralZone)
self.create_dw("Window 1")
self.create_dw("Window 2")
def create_dw(self, name):
dw = DisplayWindow(name=name)
self.centralZone.addSubWindow(dw)
dw.show()
def update_current_window(self):
""" redirect future actions to affect the newly selected window,
and update checked statuses to reflect state of selected window"""
current_window = self.centralZone.activeSubWindow()
if current_window:
self.current_dw = self.centralZone.activeSubWindow().widget()
self.fooAction.setChecked(self.current_dw.is_foo)
def set_foo(self):
self.current_dw.toggle_foo()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
ex = WindowActionMain()
ex.show()
sys.exit(app.exec_())
My actual version of DisplayWindow could be useful in many different projects, and I want to package it up so that you don't have to add a lot of code to the main window to use it. Therefore, DisplayWindow, all of its functionality and a list of available actions should be in one module, which would be imported in WindowActionMain's module. I should then be able to add more actions for DisplayWindow without changing any code in WindowActionMain. In particular, I don't want to have to write a little function like WindowActionMain.set_foo(self) just to redirect each action to the right place.
Yes, this is possible by handling the QMenu's aboutToShow signal
and considering the QGuiApplication's focusWindow (or however you get that in Qt4).
Example below shows a generic 'Window' menu acting on the frontmost window.
http://doc.qt.io/qt-4.8/qmenu.html#aboutToShow
http://doc.qt.io/qt-5/qguiapplication.html#focusWindow
def on_windowMenu_aboutToShow(self):
self.windowMenu.clear()
self.newWindowAction = QtWidgets.QAction(self)
self.newWindowAction.setShortcut("Ctrl+n")
self.newWindowAction.triggered.connect(self.on_newWindowAction)
self.newWindowAction.setText("New Window")
self.windowMenu.addAction(self.newWindowAction)
self.windowMenu.addSeparator()
playerWindows = [w for w in self.topLevelWindows() if w.type()==QtCore.Qt.Window and w.isVisible()]
for i, w in enumerate(playerWindows):
def action(i,w):
a = QtWidgets.QAction(self)
a.setText("Show Window {num} - {title}".format(num=i+1, title=w.title()))
a.triggered.connect(lambda : w.requestActivate())
a.triggered.connect(lambda : w.raise_())
self.windowMenu.addAction(a)
action(i,w)
self.windowMenu.addSeparator()
self.closeWindowAction = QtWidgets.QAction(self)
self.closeWindowAction.setShortcut("Ctrl+w")
self.closeWindowAction.triggered.connect(lambda : self.focusWindow().close())
self.closeWindowAction.setText("Close")
self.windowMenu.addAction(self.closeWindowAction)
I have created two different pyqt windows, and within one of them, by pressing a button, it should bring up another smaller window. While my code does pretty much exactly what I just dais it should do, there is a problem with the way the smaller popup window is displayed.
This is my code for displaying the windows and the button functionality:
from PyQt4 import QtGui
from EnterprisePassport import Ui_StudentEnterprisePassport
from Session_tracker import Ui_Session_tracker
class StudentEnterprisePassport(Ui_StudentEnterprisePassport):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.sessionTracker_btn.clicked.connect(self.handleButton)
self.window2 = None
def handleButton(self):
if self.window2 is None:
self.window2 = Session_tracker(self)
self.window2.show()
class Session_tracker(Ui_Session_tracker):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = StudentEnterprisePassport()
window.show()
sys.exit(app.exec_())
I can still use the functions within the window, but I can't move it, or close it, and there is no title bar. Have I done something wrong within my code for the popup window to appear like this?
Edit:
Original Session tracker window: Original window
Popup session tracker window: Popup window
In order to show the other widget in it's own window, it has to be a QMainWindow or a QDialog.
One option, if you don't want to convert your existing Session_tracker to a QDialog, is to just wrap it in a QDialog
def handleButton(self):
if self.window2 is None:
self.window2 = QtGui.QDialog(self)
lay = QtGui.QVBoxLayout()
self.window2.setLayout(lay)
self.session_tracker = Session_tracker(self.window2)
lay.addWidget(self.session_tracker)
self.window2.show()