Embed Python 3 Tkinter module as Widget in PyQT5 - python-3.x

First post and new to python so apologies if the post formatting is weird or the coding errors are dumb.
I created a module using tkinter that I want to embed into a pyQt5 MainWindow widget.
This is the tkinter module, titled Del.py, I'm trying to import.
class Delfiles(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.mw = self.mainwindow()
def mainwindow(self):
# mainwindow formatting
def dellist(self):
# delete function for buttons in mainwindow
class Results(tk.Toplevel):
def __init__(self):
tk.Toplevel.__init__(self)
# toplevel popup that appears after dellist function runs
# root = Delfiles()
# root.mainloop()
This is the part of the pyqt5 module where I've been trying to embed the tkinter module into.
class SpreadSheet(QMainWindow):
def __init__(self, rows, cols, parent=None):
super(SpreadSheet, self).__init__(parent)
self.rows = rows
self.cols = cols
self.cells = {}
self.create_table1()
self.create_table2()
deletefiles = Del.mw()
self.centralwidget = QWidget()
self.vlayout = QVBoxLayout()
self.hlayout = QHBoxLayout()
self.vlayout.addWidget(self.table1)
self.vlayout.addWidget(self.table2)
self.hlayout.addLayout(self.vlayout)
self.hlayout.addWidget(deletefiles)
self.centralwidget.setLayout(self.hlayout)
self.table1.cellDoubleClicked.connect(self.celldoubleclicked)
self.table2.installEventFilter(self)
self.setCentralWidget(self.centralwidget)
self.show()
if __name__ == __main__:
app = QApplication(sys.argv)
sheet = SpreadSheet(5, 5)
sheet.resize(1500, 900)
sheet.show()
sys.exit(app.exec_())
# https://negfeedback.blogspot.com/2017/12/a-simple-gui-spreadsheet-in-less-than.html
#link to source code for the pyqt5 module I'm working with
Every time I try to run the pyqt module with the tkinter module embedded, the tkinter module either opens on top of the pyqt5 module or i get the following error.
Exception in Tkinter callback
AttributeError: module 'Del' has no attribute 'mw'
Any help is greatly appreciated

You can't create windows in tkinter and use them in a PyQT5 application. Each GUI toolkit has a rendering model that knows nothing about the other.

Related

Start the script in PyQt5 and python3 [duplicate]

I have created a form using PyQt4 which has a push button. On this push button I want to call another python script which looks like this:
File1.py:
import sys
from PyQt4 import QtCore, QtGui
from file1_ui import Ui_Form
class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
File1_ui.py
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(400, 300)
self.pushButton = QtGui.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(120, 200, 95, 20))
self.pushButton.setObjectName(_fromUtf8("pushButton"))
self.retranslateUi(Form)
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL(_fromUtf8("clicked()")), Form.close)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton.setText(QtGui.QApplication.translate("Form", "Close", None, QtGui.QApplication.UnicodeUTF8))
File2.py
import sys
from PyQt4 import Qt
from taurus.qt.qtgui.application import TaurusApplication
app = TaurusApplication(sys.argv)
panel = Qt.QWidget()
layout = Qt.QHBoxLayout()
panel.setLayout(layout)
from taurus.qt.qtgui.panel import TaurusForm
panel = TaurusForm()
model = [ 'test/i1/1/%s' % p for p in props ]
panel.setModel(model)
panel.show()
sys.exit(app.exec_())
File1_ui.py is created from the Qtdesigner and then I am using File1.py to execute it.So File2.py when executed alone opens up a panel and displays few attributes.I want this script to be called on the button click in the first form(file1.py) which I created using Qtdesigner.Could you let me know how I could achieve this functionality.Thanks.
You will need to make some modifications to File2.py to make the appropriate calls depending on whether it is running standalone or not. When you are launching the script via File1.py there will already be a QApplication instance with event loop running, so trying to create another and run its event loop will cause problems.
Firstly, move the core part of your script into its own function. This will allow you to easily call it from File1.py. You can then handle the case where the script is running standalone and needs to create a QApplication instance and start its event loop. (I am not familiar the the taurus library you are using, but you can probably substitute TaurusApplication for QtGui.QApplication)
File2.py:
import sys
from PyQt4 import QtCore, QtGui
def runscript():
panel = QtGui.QWidget()
layout = QtGui.QHBoxLayout(panel)
return panel # Must return reference or panel will be deleted upon return
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
panel = runscript()
panel.show()
sys.exit(app.exec_())
Assuming your files are in the same directory you can simply write import File2 and use File2.runscript() to run your code. You then just need to connect the function to your pushbuttons clicked() signal to run it. The only problem here is that the reference to the QWidget returned from the runscript() function will be lost (and the object deleted) if you connect directly to runscript(). For this reason I created a method launch_script() which saves a reference in MyForm.
File1.py:
import sys
from PyQt4 import QtCore, QtGui
from file1_ui import Ui_Form
import File2
class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
# This is a bit of a hack.
self.ui.pushButton.clicked.connect(self.launch_script)
def launch_script(self):
self.panel = File2.runscript()
self.panel.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
I don't use Qt Designer, so I don't know the correct way to go about connecting the signal to launch_script(). The code I have written should work, but obviously violates OOP principles and is dependent on the name of the pushbutton widget assigned by the software.

PYQT: mainwindow closes while having second and third window open

I need some help in my current problem.
I have a window with three buttons. When pressing two of them ("GraphicButton" and "QuestionButton") a second and third window shall open. This works fine. The third button "ImportButton" is for populating a table widget in the mainwindow with a dataframe from excel.
When I press the "ImportButton" first everything works fine.
BUT when I press one of the other buttons first to open the other windows and THEN press the "ImportButton", the mainwindow and the other ones will close.
I could use some advice here.
Here is my code for main.py:
import sys
import pandas as pd
import os
from qtpy import QtWidgets, QtCore, QtGui
from ui.mainwindow import Ui_MainWindow
from ui.graphwindow import Ui_GraphWindow
from ui.questionwindow import Ui_QuestionWindow
app = QtWidgets.QApplication(sys.argv)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setWindowTitle("Test")
self.ui.ImportButton.clicked.connect(self.import_clicked)
self.ui.GraphicButton.clicked.connect(self.graphic_clicked)
self.ui.QuestionButton.clicked.connect(self.question_clicked)
def import_clicked(self):
self.ui.RefWidget.setSortingEnabled(False)
self.ui.LubWidget.setSortingEnabled(False)
self.ui.MixWidget.setSortingEnabled(False)
self.ui.RefWidget.setRowCount(0)
self.ui.LubWidget.setRowCount(0)
self.ui.MixWidget.setRowCount(0)
if self.ui.RefBoxC.currentIndex() == 0:
A = os.path.join(os.path.dirname(__file__),"./Datenbank/CO2.xlsx")
df = pd.read_excel(A)
self.ui.RefWidget.setColumnCount(len(df.columns))
self.ui.RefWidget.setRowCount(len(df.index))
for i in range(len(df.index)):
for j in range(len(df.columns)):
self.ui.RefWidget.setItem(i, j, QtWidgets.QTableWidgetItem(str(df.iat[i, j])))
self.ui.RefWidget.resizeColumnsToContents()
self.ui.RefWidget.resizeRowsToContents()
else:
A = os.path.join(os.path.dirname(__file__), "./Datenbank/PlatzhalterRef.xlsx")
df = pd.read_excel(A)
self.ui.RefWidget.setColumnCount(len(df.columns))
self.ui.RefWidget.setRowCount(len(df.index))
for i in range(len(df.index)):
for j in range(len(df.columns)):
self.ui.RefWidget.setItem(i, j, QtWidgets.QTableWidgetItem(str(df.iat[i, j])))
self.ui.RefWidget.resizeColumnsToContents()
self.ui.RefWidget.resizeRowsToContents()
self.ui.RefWidget.setSortingEnabled(True)
self.ui.LubWidget.setSortingEnabled(True)
self.ui.MixWidget.setSortingEnabled(True)
def graphic_clicked(self):
self.Gwindow = QtWidgets.QMainWindow()
self.ui = Ui_GraphWindow()
self.ui.setupUi(self.Gwindow)
self.Gwindow.show()
def question_clicked(self):
self.Questwindow = QtWidgets.QMainWindow()
self.ui = Ui_QuestionWindow()
self.ui.setupUi(self.Questwindow)
self.Questwindow.show()
window = MainWindow()
window.show()
sys.exit(app.exec_())
Disclaimer: the solution provided by this answer has not been tested and may be incomplete.
When you click either the GraphicButton or QuestionButton,
self.ui = Ui_GraphWindow()
or
self.ui = Ui_QuestionWindow()
This will modify self.ui. When the ImportButton is clicked, self.ui will refer to the other windows. This, I believe, is unintentional.
When the commands in import_clicked() are run, there may be references to undefined classes, widgets, and whatnot.
self.ui.RefWidget.setSortingEnabled(False)
I'm guessing RefWidget is not defined in Ui_QuestionWindow or Ui_GraphWindow.
To solve this, try adding
def import_clicked(self):
self.ui = Ui_MainWindow() # set self.ui to refer to a MainWindow
# ...
and see if it works. (Warning: a new MainWindow may be created and the old MainWindow be left forsaken. Again, I haven't tested this to see if it does create a new MainWindow but my intuition tells me that it does.)
EDIT: Above suggestion in strikethrough did not work for OP.
If further trouble and chaos ensues, consider having three separate member variables instead of a single self.ui.
def __init__(self, parent = None):
super().__init__(parent)
self.uiMain = Ui_MainWindow() # new member variable: self.uiMain
# ...
def import_clicked(self):
self.uiMain.RefWidget.setSortingEnabled(False)
self.uiMain.LubWidget.setSortingEnabled(False)
self.uiMain.MixWidget.setSortingEnabled(False)
# ...
def graphic_clicked(self):
self.Gwindow = QtWidgets.QMainWindow()
self.uiGraphic = Ui_GraphWindow() # new member variable: self.uiGraphic
# ...
def question_clicked(self):
self.Questwindow = QtWidgets.QMainWindow()
self.uiQuestion = Ui_QuestionWindow() # new member variable: self.uiQuestion
# ...

Function is not run when connecting Button to it in PyQt4

I m new to PyQt4 and having problems when trying to connect a button to a function.
I m using PyQt 4.11.4.
Neither the clicked.connect method nor the line in the comment below seemed to work.
from PyQt4 import QtGui, QtCore
import sys
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
def setupUi(self, Window):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(200, 200)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setGeometry(0,0,100,100)
MainWindow.setCentralWidget(self.centralwidget)
self.pushButton = QtGui.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(100, 50, 55, 20))
self.pushButton.setText("Run")
self.pushButton.clicked.connect(self.run)
#OR QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL('clicked()'),self.run)
def run(self):
print("ok")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
Window().setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
First of all, by placing statements directly after the __name__ == "__main__" test you introduce global variables. For instance the MainWindow variable is global and is subsequently altered in the Window.setupUi method. This is undesirable. It's better to create a main function and call only that. For example by changing those lines into this...
def main():
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
Window().setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
you will get a run-time error and thus notice something's wrong.
By the way, it is the convention in Python to start class names with an upper case character and objects with a lower case. Therefore, at first glance I thought that MainWindow was a class. It is, however, an object and should better be renamed to mainWindow. Notice how the StackOverflow syntax highlighting colors all identifiers that start with an capital letter light blue?
So, the issue with the signal is that you create two main window objects: first by MainWindow = QtGui.QMainWindow() and then on the next line by Window().setupUi(MainWindow). On that second line you call setupUi with the self parameter set to a temporary Window object, and the Window parameter set to a QtGui.QMainWindow object (MainWindow). It's not surprising that this doesn't work, it is actually a bit surprising it does something at all.
Finally, it is strongly recommended to use layouts in Qt to arrange the widgets. This makes the calls to setGeometry() superfluous. Adding widgets to a layout also set's their parent, so you don't need to do this separately then. I think you definitely should read the docs on layout management (except the last section on writing your own layout manager).
Apply all the advice above and you get something like this...
from PyQt4 import QtGui, QtCore
import sys
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self._setupUi()
def _setupUi(self):
self.resize(200, 200)
# the central widget is called my widget to prevent clashes with
# the centralWidget() function.
self.mainWidget = QtGui.QWidget()
self.setCentralWidget(self.mainWidget)
self.mainLayout = QtGui.QVBoxLayout()
self.mainWidget.setLayout(self.mainLayout)
self.pushButton = QtGui.QPushButton()
self.pushButton.setText("Run")
self.mainLayout.addWidget(self.pushButton)
self.pushButton.clicked.connect(self.run)
def run(self):
print("ok")
def main():
app = QtGui.QApplication(sys.argv)
mainWindow = Window()
mainWindow.setObjectName("mainWindow") # can be omitted.
mainWindow.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

add pyqtgraph (plot) into QApplication

hy,
soooo, i created the MainWindow.ui file with the QTDesigner. Then i import this gui with following command into my .py file:
form_class = uic.loadUiType("ess_project.ui")[0]
What is the difference if i compile this .ui file with pyuic4 ?
(every time i compiled my .ui file i got following error:
RuntimeError: the sip module implements API v11.0 to v11.1 but the PyQt4.QtCore module requires API v10.1
The MainWindow create the first window, where all buttons etc. are placed.
class MainWindow(QtGui.QMainWindow, form_class):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
PlotWindow.__init__(self)
self.setupUi(self)
self.pb_send.clicked.connect(self.pb_send_clicked)
self.pb_open.clicked.connect(self.pb_open_clicked)
self.pb_exit.clicked.connect(self.pb_exit_clicked)
self.comboBox.currentIndexChanged.connect(self.combo_box_changed)
furthermore i have a second class named "PlotWindow". This class looks like this:
class PlotWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.w = QtGui.QMainWindow()
self.cw = pg.GraphicsLayoutWidget()
self.w.show()
self.w.resize(900,600)
self.w.setCentralWidget(self.cw)
self.w.setWindowTitle('pyqtgraph: G-CODE')
self.p = self.cw.addPlot(row=0, col=0)
now as you can see, the PloWindow - class create a second Window.
How can i implement the pg.GraphicsLayoutWidget() into the MainWindow - class ??
not sure if this can help you ?!? :
def main():
app = QtGui.QApplication([])
myWindow = MainWindow(None)
myWindow.show()
app.exec_()
if __name__ == '__main__':
main()
I am using python3 !!!
feel FREE to comment :)
thanks !
To place any pyqtgraph widgets inside your application, you add a placeholder widget and "promote" it to the pg class that you want. See: http://www.pyqtgraph.org/documentation/how_to_use.html#embedding-widgets-inside-pyqt-applications

How to display a custom dialog using PyQt and QtDesigner to design the custom dialog?

I have designed 2 widgets - one is the main application widget and a custom widget which would allow me to set the preferences in my main application. They are named - main and child.
Now, I can't get the child widget to show when I click the button in the main application.
Tried to learn from the Rapid GUI programming using Python and Qt book, but the example given there is for a hand coded form and not designed using QtDesigner. I am getting confused. Kindly help.
My code so far is this-
import serial, sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from main import Ui_Form # main.py and child.py are the ui
from child import Ui_Form as Child_Form # files generated using pyuic4
class Main(QMainWindow):
def __init__(self, parent = None):
super(Main, self).__init__(parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.connect(self.ui.btnLaunch, SIGNAL("clicked()"), self.show)
def show(self):
dialog = QDialog()
dialog.ui = Child_Form()
dialog.ui.setupUi(self)
if __name__ == "__main__":
app = QApplication(sys.argv)
myapp = Main()
myapp.show()
sys.exit(app.exec_())
However, nothing happens when I try to launch this program.
Instead of this code:
self.connect(self.ui.btnLaunch, SIGNAL("clicked()"), self.show)
def show(self):
dialog = QDialog()
dialog.ui = Child_Form()
dialog.ui.setupUi(self)
try with this, it should work:
self.connect(self.ui.btnLaunch, SIGNAL("clicked()"), self.showDialog)
def showDialog(self):
dialog = QDialog()
dialog.ui = Child_Form()
dialog.ui.setupUi(self)
dialog.show()

Resources