I recently started using qt to build a python GUI. I have two problems I can't quite find the solutions to. the code below is a sample of what I need to build.
1: Check which radio button from a list of radio buttons in a vertical layout has been clicked. In the GUI it only selects one radio button out of all others available in the layout. How do I perceive which has been clicked?
2:I would like to add the clicked value to a JSON object but I believe that is a simple if statement of if this then that. Unless it's more complicated in which case please push me in the right direction.
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(596, 466)
self.verticalLayoutWidget = QtWidgets.QWidget(Dialog)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(180, 70, 61, 80))
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.that = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.that.setObjectName("that")
self.verticalLayout.addWidget(self.that)
self.thi = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.thi.setObjectName("thi")
self.verticalLayout.addWidget(self.thi)
self.sure = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.sure.setObjectName("sure")
self.verticalLayout.addWidget(self.sure)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.that.setText(_translate("Dialog", "that"))
self.thi.setText(_translate("Dialog", "this"))
self.sure.setText(_translate("Dialog", "sure"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
There is a nice way to solve this using Qt Designer, which allows you to group your buttons into a QButtonGroup, and then connect to its buttonClicked signal to get the button that was clicked.
All you need to do is, in Qt Designer, select all the buttons (using Ctrl+click), then right-click one of the buttons and select Assign to button group -> New button group. This will create a new button-group object and automatically add all the buttons to it.
After re-generating your gui module, you can then do somehting like this:
ui.radioButtonGroup.buttonClicked.connect(radioButtonClicked)
def radioButtonClicked(button):
print(button.text())
I think you need something like this (not tested)
# Set Default
self.thi.setChecked(True)
# create a signal
QtCore.QObject.connect(self.that,
QtCore.SIGNAL("toggled(bool)"),
self.radio_clicked)
then create a function
def self.radio_clicked(self):
print 'ive been clicked' # work from here
Related
I which to bring back to initial state an Undocked or floated QDockWidget with a QPushButton.
from PyQt5 import QtCore, QtGui, QtWidgets
class Mainwindow(object):
def setupUi(self, window):
window.setObjectName("window")
window.resize(309, 148)
self.centralwidget = QtWidgets.QWidget(window)
self.centralwidget.setObjectName("centralwidget")
self.Undock_btn = QtWidgets.QPushButton(self.centralwidget)
self.Undock_btn.setGeometry(QtCore.QRect(4, 4, 100, 22))
self.Undock_btn.setStyleSheet("background: rgba(255, 217, 90, 255)\n")
self.Undock_btn.setObjectName("Undock_btn")
self.ReDock_btn = QtWidgets.QPushButton(self.centralwidget)
self.ReDock_btn.setGeometry(QtCore.QRect(110, 4, 96, 22))
self.ReDock_btn.setStyleSheet("background:rgba(9, 17, 188, 109);")
self.ReDock_btn.setObjectName("ReDock_btn")
self.dockw = QtWidgets.QDockWidget(self.centralwidget)
self.dockw.setTitleBarWidget(None)
self.dockw.setGeometry(QtCore.QRect(4, 34, 200, 110))
self.dockw.setStyleSheet("background:rgba( 0,188, 0, 29);\n")
self.dockw.setObjectName("dockw")
self.dockWidgetContents = QtWidgets.QWidget()
self.dockWidgetContents.setObjectName("dockWidgetContents")
self.dockw.setWidget(self.dockWidgetContents)
window.setCentralWidget(self.centralwidget)
self.retranslateUi(window)
QtCore.QMetaObject.connectSlotsByName(window)
#-----------------------------------------------------------------
self.Undock_btn.setCheckable(True)
self.connexions()
def connexions(self):
self.Undock_btn.clicked.connect(self.Method_Float_it)
self.ReDock_btn.clicked.connect(self.Method_BringBack)
def Method_Float_it(self):
print("Method_Float_it")
self.dockw.setFloating(True)
if self.dockw.isFloating():
print("is Floating now...")
return True
def Method_BringBack(self):
self.dockw.setFloating(False)
self.dockw.RestoreState(True)
def retranslateUi(self, window):
_translate = QtCore.QCoreApplication.translate
window.setWindowTitle(_translate("window", "GUI"))
self.Undock_btn.setText(_translate("window", "UnDock Button"))
self.ReDock_btn.setText(_translate("window", "Bring back button"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
ui = Mainwindow()
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
image of when it's floated after pressed QPushButton
The Problem is: after I undocked the QDockWidget with first button, the second button fails to bring it back to normal (initial state)
The "main" issue is that you're not correctly adding the dock widget to the window, as the right way to do it is using the addDockWidget() method of QMainWindow.
What you actually did was to create the dock widget as a child of the central widget, and that's not a valid approach.
Your first function "works" just because when setFloating(True) is called, QDockWidget changes its window flags and ensures that it becomes a top level window.
The restore function doesn't work because the dock widget has never been correctly added to the main window, so it has no reference to know where it should "dock back".
The solution, theoretically, would be to add this line after the dock widget is created:
window.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dockw)
But, it would be only a partial solution, as your code has two other major problems.
You are not using layout managers; this will become a serious problem whenever any resizing happens to or inside the window, including trying to drag a floating dock widget on the sides of the window: for instance, if the window is not wide enough, dragging the dock widget on the side will result in partially (or completely) hiding its buttons;
You are modifying a file generated by pyuic; this is considered bad practice for lots of reasons, and while your program "works" right now, sooner or later (but most probably sooner) you'll face unexpected behavior and confusion about the implementation; those files are only intended to be imported, as explained in the guidelines about using Designer;
There are two other (relatively) minor issues:
I don't know what RestoreState is, but it certainly is not a member of QDockWidget, nor of Qt with the uppercase R, as the only restoreState() functions in Qt (for QMainWindow, QSplitter, etc) require a QByteArray, not a bool;
only classes and constants should have capitalized names, not functions (nor variables);
I fixed your code, it is working now as expected. All variables functions and methods should be either some_function_name or someFunctionName, the former is called C style and the latter Java style. Further, your class has to inherit from QMainWindow, and a QLayout has to be added to every QWidget. Then, the subwidgets are added to the QLayout with QLayout.addWidget. Following the code, where i added some comments for explanation.
#!/usr/bin/python3
#-*-coding: utf-8-*-
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Mainwindow(QtWidgets.QMainWindow):
def setupUI(self):
self.setObjectName("window")
self.resize(309, 148)
self.centralWid = QtWidgets.QWidget(self) # not naming it centralWidget, because that would override the centralWidget() function of QMainWindow
self.centralWid.setObjectName("centralwidget")
self.centralLay = QtWidgets.QHBoxLayout(self.centralWid) # create a layout
self.centralWid.setLayout(self.centralLay) # and set it on the central widget
self.setCentralWidget(self.centralWid) # set centralWidget as the centralWidget of the window
self.undockButton = QtWidgets.QPushButton(self.centralWid)
self.undockButton.setStyleSheet("background: rgba(255, 217, 90, 255);")
self.undockButton.setObjectName("undockbutton")
self.centralLay.addWidget(self.undockButton)
self.redockButton = QtWidgets.QPushButton(self.centralWid)
self.redockButton.setStyleSheet("background: rgba(9, 17, 188, 109);")
self.redockButton.setObjectName("redockButton")
self.centralLay.addWidget(self.redockButton)
self.dock = QtWidgets.QDockWidget("Dock title", self.centralWid)
self.dock.setTitleBarWidget(None)
self.dock.setStyleSheet("background: rgba( 0,188, 0, 29);")
self.dock.setObjectName("dock")
self.dockContents = QtWidgets.QWidget()
self.dockContents.setObjectName("dockcontents")
self.dock.setWidget(self.dockContents)
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dock)
self.translateUI()
QtCore.QMetaObject.connectSlotsByName(self)
self.connectSlots()
def connectSlots(self):
self.undockButton.clicked.connect(self.undock)
self.redockButton.clicked.connect(self.redock)
def undock(self):
self.dock.setFloating(True)
def redock(self):
if self.dock.isFloating():
self.dock.setFloating(False)
def translateUI(self):
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("window", "Window"))
self.undockButton.setText(_translate("window", "Undock"))
self.redockButton.setText(_translate("window", "Redock"))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = Mainwindow()
mainWin.setupUI()
mainWin.show()
sys.exit(app.exec_())
I am trying to get a button event handler working using Qt Designer.
I am using Anaconda-Spyder with Python 3.6
The form appears but the button btn_browse does not function. The line edit box has a cursor in it and you can type into it.
The Python file generated automatically from the ui is below. It is called file_reader.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(640, 320)
self.btn_browse = QtWidgets.QPushButton(Dialog)
self.btn_browse.setGeometry(QtCore.QRect(220, 50, 113, 32))
self.btn_browse.setObjectName("btn_browse")
self.lineEdit = QtWidgets.QLineEdit(Dialog)
self.lineEdit.setGeometry(QtCore.QRect(170, 120, 241, 131))
self.lineEdit.setObjectName("lineEdit")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.btn_browse.setText(_translate("Dialog", "MyButton"))
The code I have used (pretty much from the QtDesigner Docs site) is
from PyQt5 import QtGui
from PyQt5.QtWidgets import QDialog, QApplication
from file_reader import Ui_Dialog
class Dialog(QDialog):
def __init__(self):
super(Dialog, self).__init__()
# Set up the user interface from Designer.
self.ui = Ui_Dialog()
self.ui.setupUi(self)
# Make some local modifications.
self.ui.colorDepthCombo.addItem("2 colors (1 bit per pixel)")
# Connect up the buttons.
self.ui.btn_browse.clicked.connect(self.browse_folder)
def browse_folder(self):
#exit
print("Hello")
#self.textBrowser.clear() # In case there are any existing elements in the list
directory = QtGui.QFileDialog.getExistingDirectory(self,"Pick a folder")
# execute getExistingDirectory dialog and set the directory variable to be equal
# to the user selected directory
if directory: # if user didn't pick a directory don't continue
for file_name in os.listdir(directory): # for all files, if any, in the directory
self.listWidget.addItem(file_name) # add file to the listWidget
import sys
app = QApplication(sys.argv)
window = Dialog() #Also tried QDialog() here
ui = Ui_Dialog()
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
I don't think the function browse_folder is being called. I think the issue might be the QDialog class being used rather than QMainForm. I
I am working on that. Also, I am unsure what the x switch in the ui convertor does.
I have looked at several answers here and can't see what I am doing wrong.
Your code has the following problems:
You are not creating a Dialog object, but a QDialog filled with Ui_Dialog that does not have the browse_folder method or the connection.
QFileDialog is part of QtWidgets, it is not part of QtGui, you are probably using an example of PyQt4.
I'm assuming that listWidget is from Ui_Dialog so you must sign in through ui.
from PyQt5.QtWidgets import QDialog, QApplication, QFileDialog
from file_reader import Ui_Dialog
import os
class Dialog(QDialog):
def __init__(self):
super(Dialog, self).__init__()
# Set up the user interface from Designer.
self.ui = Ui_Dialog()
self.ui.setupUi(self)
# Make some local modifications.
self.ui.colorDepthCombo.addItem("2 colors (1 bit per pixel)")
# Connect up the buttons.
self.ui.btn_browse.clicked.connect(self.browse_folder)
def browse_folder(self):
#exit
print("Hello")
#self.textBrowser.clear() # In case there are any existing elements in the list
directory = QFileDialog.getExistingDirectory(self,"Pick a folder")
# execute getExistingDirectory dialog and set the directory variable to be equal
# to the user selected directory
if directory: # if user didn't pick a directory don't continue
for file_name in os.listdir(directory): # for all files, if any, in the directory
self.ui.listWidget.addItem(file_name) # add file to the listWidget
import sys
app = QApplication(sys.argv)
window = Dialog()
window.show()
sys.exit(app.exec_())
The code is smaller version I put together to demonstrate what I am trying to do. I just need to get information from a QButtonGroup of radio buttons. Specifically the text of which one has been clicked. However, when I run click the button in the GUI python crashes. There is no error message so I can't pinpoint the cause. Below is the example code, below that is the image show upon clicking a radio button:
Working earlier with a more inefficient method I got to sending commands to the server however the same error occurred when I tried to save the changes to the couchDB document specifically using db.save(doc) command.
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(400, 300)
self.verticalLayoutWidget = QtWidgets.QWidget(Dialog)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(130, 80, 101, 80))
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.rad2 = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.rad2.setObjectName("rad2")
self.group1 = QtWidgets.QButtonGroup(Dialog)
self.group1.setObjectName("group1")
self.group1.addButton(self.rad2)
self.verticalLayout.addWidget(self.rad2)
self.rad3 = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.rad3.setObjectName("rad3")
self.group1.addButton(self.rad3)
self.verticalLayout.addWidget(self.rad3)
self.rad1 = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.rad1.setObjectName("rad1")
self.group1.addButton(self.rad1)
self.verticalLayout.addWidget(self.rad1)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def printText(button):
print(button.text())
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.rad2.setText(_translate("Dialog", "RadioButton"))
self.rad3.setText(_translate("Dialog", "RadioButton"))
self.rad1.setText(_translate("Dialog", "RadioButton"))
ui.group1.buttonClicked.connect(self.printText)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
You need to define the slot with a self argument:
def printText(self, button):
print(button.text())
In a program, I want to accept drag and drop of a file into a QTextExit in order to edit certain parts of it.
The drag and drop works fine, however after a file is dropped in the QTextEdit, the QTextEdit's cursor becomes frozen (stops blinking and can no longer be moved).
Here is a minimal example:
After drag-and-drop:
(d&d works fine, but cursor freezes)
I can edit the content in the textEdit, but the cursor remains visible after the textEdit loses focus.
Code:
# -*- coding: utf-8 -*-
import sys
from PyQt5 import Qt
if __name__ == '__main__':
Application = Qt.QApplication(sys.argv)
from Drag_drop_window import Ui_Form # import QtDesigner file
class override_textEdit(Qt.QTextEdit): # override drop event for QTextEdit
drop_accepted_signal = Qt.pyqtSignal(str) # the signal sends the file name to other widget
def __init__(self):
super(override_textEdit,self).__init__()
self.setText("123")
self.setAcceptDrops(True)
def dropEvent(self, event):
if len(event.mimeData().urls())==1: # accept event when only one file was dropped
event.accept()
self.drop_accepted_signal.emit(event.mimeData().urls()[0].toLocalFile())
else:
Qt.QMessageBox.critical(self,"Accept Single File Only","Accept Single File Only",Qt.QMessageBox.Abort)
event.ignore()
class myWidget(Qt.QWidget):
def __init__(self):
super(myWidget, self).__init__()
self.main = Ui_Form()
self.main.setupUi(self)
self.main.textEdit = override_textEdit()
self.main.verticalLayout.addWidget(self.main.textEdit)
self.main.textEdit.drop_accepted_signal.connect(self.slot)
self.show()
def slot(self,filename):
self.main.lineEdit.setText(filename) # display file name in lineEdit
if __name__ == '__main__':
my_Qt_Program = myWidget()
my_Qt_Program.show()
sys.exit(Application.exec_())
Drag_drop_window.py generated by QtDesigner
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'Drag_drop_window.ui'
#
# Created: Sun Apr 5 17:53:03 2015
# by: PyQt5 UI code generator 5.3.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setObjectName("verticalLayout")
self.lineEdit = QtWidgets.QLineEdit(Form)
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
I have found that adding the following four lines to the end of the dropEvent makes things work:
mimeData = QtCore.QMimeData()
mimeData.setText("")
dummyEvent = QtGui.QDropEvent(event.posF(), event.possibleActions(),
mimeData, event.mouseButtons(), event.keyboardModifiers())
super(override_textEdit, self).dropEvent(dummyEvent)
You've overridden the dropEvent method of the QTextEdit control, but you're not calling the overridden superclass method. I guess that there is some cleanup code in the overridden method that needs to run in order to sort out the issues you were having with the cursor. However, simply calling the superclass method with the drop event, i.e.
super(override_textEdit, self).dropEvent(event)
doesn't do what you are hoping for. This enters the URL of the dropped file into the text-edit control.
I didn't find that any combination of calling accept(), ignore() or setDropAction(Qt.IgnoreAction) before calling the superclass dropEvent had any effect. I suspect that the superclass method makes its own decisions on whether to accept or ignore the event, which may override what your subclass will have done.
So instead I create a 'fake' drag-and-drop event, identical to the one received except that the text data is empty, and pass this fake event onto the superclass. Of course, the superclass is welcome to insert this empty text somewhere if it wants to, but if it does it's not going to have any effect.
I would like to display a window with a QwebView widget in Pyside. For this I use some code generated by QtCreator:
#code generated by QtCreator:
from PySide import QtCore, QtGui
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(400, 300)
self.centralWidget = QtGui.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")
self.webView = QtWebKit.QWebView(self.centralWidget)
self.webView.setGeometry(QtCore.QRect(10, 20, 380, 270))
self.webView.setUrl(QtCore.QUrl("file:///C:/pdf_folder/test.pdf"))
self.webView.setObjectName("webView")
MainWindow.setCentralWidget(self.centralWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
from PySide import QtWebKit
# My code:
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
APP = QtGui.QApplication(sys.argv)
MW = MainWindow()
MW.show()
sys.exit(APP.exec_())
I am sure to have a pdf file in the specified path, but when I run my script, the pdf file is never displayed in my window.
Do you know what I am doing wrong ?
I saw this topic Is it possible to get QWebKit to display pdf files?, but the answer don't work for me (after changing PyQt to Pyside in the import lines).
I also saw this topic PDF with QWebView: missing refresh/repaint after loading, the workaround (using a timer before loading) work for me. however I don't think that using a timer to load a file is a good way to solve the problem.
And, mainly, the code that I used for Ui_MainWindow is generated with QtCreator, I didn't change it and I don't want to change it by myself (without using QtCreator). It is just a simple form for a window with only one widget QtWebKit.QWebView in which I want to load a file. It should work without weird workaround. Why the code automatically generated don't work ? Am I using QtCreator in a wrong way ?
You have to enable QWebView's plugins:
self.webView = QtWebKit.QWebView(self.centralWidget)
self.webView.settings().setAttribute(QWebSettings.PluginsEnabled, True)
also try to set the QWebView URL after showing the main window.
MW = MainWindow()
MW.show()
MW.ui.webView.setUrl(QtCore.QUrl("file:///C:/pdf_folder/test.pdf"))
I think the paint events has to do with the fact you don't see the pdf file.