How do I update widgets in the window and add new widgets to the window in PyGObject? - gtk

I have a window set up with a few widgets but I want those widgets' information to be updated after some user input (e.g. button click). Also, I want an event handler to be able to add a new widget to the window.
I have attached an attempt at the below simple version of my question. Obviously it does not work though.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gdk, Gtk
class Button(Gtk.Box):
def __init__(self, message, label, window_grid):
Gtk.Box.__init__(self, spacing=6)
self.set_border_width(10)
self.label = label
self.window_grid = window_grid
button = Gtk.Button.new_with_label(message)
button.connect("clicked", self.on_click)
self.pack_start(button, True, True, 0)
def on_click(self, widget):
# Change/update a label in the window_grid
self.label = LabelBox("Changed the label")
self.label.queue_draw()
# Add a new label to the window_grid
new_label = LabelBox("New label")
self.window_grid.attach(new_label, 0, 2, 1, 1)
class LabelBox(Gtk.Box):
def __init__(self, message):
Gtk.Box.__init__(self, spacing=6)
self.set_border_width(10)
label = Gtk.Label(message)
self.pack_start(label, True, True, 0)
win = Gtk.Window()
window_grid = Gtk.Grid()
label = LabelBox("This is a label")
button = Button("Test", label, window_grid)
window_grid.attach(label, 0, 0, 1, 1)
window_grid.attach(button, 0, 1, 2, 2)
win.add(window_grid)
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

Your code structure is poorly formatted. This code worked for me:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
import sys
class GUI:
def __init__(self):
self.win = Gtk.Window()
self.window_grid = Gtk.Grid()
box = Gtk.Box()
button = Gtk.Button.new_with_label("Test")
button.connect("clicked", self.on_click)
self.label = Gtk.Label("This is a label")
self.window_grid.attach(self.label, 0, 0, 1, 1)
self.window_grid.attach(button, 0, 1, 2, 2)
self.win.add(self.window_grid)
self.win.connect("delete-event", Gtk.main_quit)
self.win.show_all()
def on_click(self, widget):
# Change/update a label in the window_grid
self.label.set_label('Label changed')
label = Gtk.Label("Another label")
self.window_grid.attach(label, 2, 1, 2, 2)
self.win.show_all()
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
Also keep #andlabs comment in mind, widgets are hidden by default.

As already said, your code logic ain't good. You must try to understand how to design your applications. Anyway, I've managed to get your code working to fit your question:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class Button(Gtk.Box):
def __init__(self, message, label, window_grid):
Gtk.Box.__init__(self, spacing=6)
self.set_border_width(10)
self.label = label
self.window_grid = window_grid
button = Gtk.Button.new_with_label(message)
button.connect("clicked", self.on_click)
self.pack_start(button, True, True, 0)
def on_click(self, widget):
# Change/update a label in the window_grid
self.label.label.set_text("Changed the lable")
# Add a new label to the window_grid
new_label = LabelBox("New label")
self.window_grid.attach(new_label, 0, 2, 1, 1)
new_label.show_all()
class LabelBox(Gtk.Box):
def __init__(self, message):
Gtk.Box.__init__(self, spacing=6)
self.set_border_width(10)
self.label = Gtk.Label(message)
self.pack_start(self.label, True, True, 0)
win = Gtk.Window()
window_grid = Gtk.Grid()
label = LabelBox("This is a label")
button = Button("Test", label, window_grid)
window_grid.attach(label, 0, 0, 1, 1)
window_grid.attach(button, 0, 1, 1, 1)
win.add(window_grid)
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
Compare it to yours to see the mistakes you've made. There was no need to wrap the label and the button inside GtkBox.

Related

Voila not clearing output/dispalying new output

I am trying to get an ipywidget button to change colour when clicked. I figured a way to do it as below
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
def clear(b):
clear_output()
display(HBox1)
pdf_btn.on_click(clear)
display(HBox)
When inputting this code in Jupyter Notebook and rendering through Voila nothing happens.
Any ideas why ? And any suggestions ?
You can just update the button style maybe? Like so:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
def clear(b):
pdf_btn.button_style="success"
pdf_btn.description="PDF done"
pdf_btn.on_click(clear)
display(HBox)
Note that your code fails in JupyterLab.
Voila is much more similar to JupyterLab's rendering machinery than the classic interface. For now, it is best to use JupyterLab in conjunction with developing for Voila. (Note that this will change soon as the underlying machinery for what is now the traditional Jupyter notebook interface will soon run on machinery more in line with JupyterLab, see Build Jupyter Notebook v7 off of JupyterLab components. A lot of the old code / approaches will then consistently not work and either interface will be as suitable for developing with Voila in mind.)
When your code fails in JupyterLab it logs that to the console, similar to as shown here. I suspect you could follow Jason's advice, what I reference in my reply, which is here, if you actually want the other button there. (I guess I should say if you actually want the other HBox there since for some reason you have each button in a separate HBox in your code.) In other words, you'd need to add in how to handle the output from HBox1 correctly as part of the main output. Yours is going to the JupyterLab Log console as it is now.
So one option is to add HBox1 in as a displayed item, yet hide it initially:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
HBox1.layout.visibility = 'hidden' #based on https://github.com/jupyter-widgets/ipywidgets/issues/674#issuecomment-234321603
def clear(b):
HBox1.layout.visibility = 'visible'
HBox.layout.display = 'none' #based on https://stackoverflow.com/a/54134344/8508004
pdf_btn.on_click(clear)
display(HBox)
display(HBox1)
You could also make an overarching vertical box for the items and then toggle which one it contains, similar to here. This is the 'cleanest' option I'll list here, other than just having one button & changing the button itself:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
vb = VBox(children = [HBox])
def clear(b):
vb.children = [HBox1]
pdf_btn.on_click(clear)
display(vb)
('cleanest' in regards to it not creating extra space in the output area.)
Or combine the vertical box approach with the approach of toggling off via the layout settings:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
HBox1.layout.visibility = 'hidden' #based on https://github.com/jupyter-widgets/ipywidgets/issues/674#issuecomment-234321603
vb = VBox(children = [HBox, HBox1])
def clear(b):
HBox1.layout.visibility = 'visible'
HBox.layout.display = 'none' #based on https://stackoverflow.com/a/54134344/8508004
pdf_btn.on_click(clear)
display(vb)
And if you want to fully leverage Jupyter's display system further, combine it with an overarching out so you can use print(), too:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
out = widgets.Output()
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
vb = VBox(children = [HBox])
def clear(b):
vb.children = [HBox1]
with out:
print('Enjoy!')
pdf_btn.on_click(clear)
with out:
display(vb)
out

PyQt5 using Drop_groupBox() from another file

I have a groupBox in my PyQt5-Application which serves as a dropzone, where the user can upload files and the dropEvent prints a list of the filenames that were dragged into the dropzone and writes them to the listWidget. I have slightly changed the original code from here:
dropfiles.py
# -*- coding: utf-8 -*-
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
import os
from PyQt5 import QtCore, QtGui, QtWidgets
class Drop_groupBox(QtWidgets.QGroupBox):
dropped = QtCore.pyqtSignal(list)
def __init__(self, parent):
super().__init__(parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, e):
if e.mimeData().hasUrls():
e.accept()
else:
e.ignore()
def dropEvent(self, e):
list_of_files = [url.toLocalFile() for url in e.mimeData().urls() if os.path.isfile(url.toLocalFile())]
self.dropped.emit(list_of_files)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(658, 449)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
MainWindow.setSizePolicy(sizePolicy)
MainWindow.setMinimumSize(QtCore.QSize(658, 449))
MainWindow.setMaximumSize(QtCore.QSize(658, 449))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_3 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_3.setObjectName("gridLayout_3")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.label_Files = QtWidgets.QLabel(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label_Files.sizePolicy().hasHeightForWidth())
self.label_Files.setSizePolicy(sizePolicy)
self.label_Files.setMinimumSize(QtCore.QSize(122, 20))
self.label_Files.setMaximumSize(QtCore.QSize(122, 20))
self.label_Files.setObjectName("label_Files")
self.gridLayout.addWidget(self.label_Files, 0, 0, 1, 1)
self.listWidget_Files = QtWidgets.QListWidget(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.listWidget_Files.sizePolicy().hasHeightForWidth())
self.listWidget_Files.setSizePolicy(sizePolicy)
self.listWidget_Files.setMinimumSize(QtCore.QSize(256, 341))
self.listWidget_Files.setMaximumSize(QtCore.QSize(256, 341))
self.listWidget_Files.setObjectName("listWidget_Files")
self.gridLayout.addWidget(self.listWidget_Files, 1, 0, 1, 1)
self.gridLayout_3.addLayout(self.gridLayout, 0, 0, 1, 1)
# self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox = Drop_groupBox(self.centralwidget)
self.groupBox.dropped.connect(self.fill_fileslist)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth())
self.groupBox.setSizePolicy(sizePolicy)
self.groupBox.setMinimumSize(QtCore.QSize(300, 300))
self.groupBox.setMaximumSize(QtCore.QSize(400, 300))
self.groupBox.setTitle("")
self.groupBox.setObjectName("groupBox")
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox)
self.gridLayout_2.setObjectName("gridLayout_2")
self.label = QtWidgets.QLabel(self.groupBox)
self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
self.gridLayout_3.addWidget(self.groupBox, 0, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 658, 19))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "TestCase"))
self.label_Files.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:12pt; font-weight:600;\">Selected Files</span></p></body></html>"))
self.label.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:16pt; font-weight:600;\">Drop Files Here!</span></p></body></html>"))
def fill_fileslist(self, files_list):
self.listWidget_Files.addItems(files_list)
print(files_list)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
This works perfectly fine, when I have all the code in one file. But now my problem is that I am designing a gui with the PyQt Designer and I want to separate the "gui"-file from the file with the programming logic (programming functions), so that when I change something in the gui and convert it to a python file (with pyuic), the functions not defined in the Designer won't be overwritten. So this is what I have tried:
mainwindow.py (the gui file)
# -*- coding: utf-8 -*-
#
# 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_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(658, 449)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
MainWindow.setSizePolicy(sizePolicy)
MainWindow.setMinimumSize(QtCore.QSize(658, 449))
MainWindow.setMaximumSize(QtCore.QSize(658, 449))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_3 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_3.setObjectName("gridLayout_3")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.label_Files = QtWidgets.QLabel(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label_Files.sizePolicy().hasHeightForWidth())
self.label_Files.setSizePolicy(sizePolicy)
self.label_Files.setMinimumSize(QtCore.QSize(122, 20))
self.label_Files.setMaximumSize(QtCore.QSize(122, 20))
self.label_Files.setObjectName("label_Files")
self.gridLayout.addWidget(self.label_Files, 0, 0, 1, 1)
self.listWidget_Files = QtWidgets.QListWidget(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.listWidget_Files.sizePolicy().hasHeightForWidth())
self.listWidget_Files.setSizePolicy(sizePolicy)
self.listWidget_Files.setMinimumSize(QtCore.QSize(256, 341))
self.listWidget_Files.setMaximumSize(QtCore.QSize(256, 341))
self.listWidget_Files.setObjectName("listWidget_Files")
self.gridLayout.addWidget(self.listWidget_Files, 1, 0, 1, 1)
self.gridLayout_3.addLayout(self.gridLayout, 0, 0, 1, 1)
self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth())
self.groupBox.setSizePolicy(sizePolicy)
self.groupBox.setMinimumSize(QtCore.QSize(300, 300))
self.groupBox.setMaximumSize(QtCore.QSize(400, 300))
self.groupBox.setTitle("")
self.groupBox.setObjectName("groupBox")
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox)
self.gridLayout_2.setObjectName("gridLayout_2")
self.label = QtWidgets.QLabel(self.groupBox)
self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
self.gridLayout_3.addWidget(self.groupBox, 0, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 658, 19))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "TestCase"))
self.label_Files.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:12pt; font-weight:600;\">Selected Files</span></p></body></html>"))
self.label.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:16pt; font-weight:600;\">Drop Files Here!</span></p></body></html>"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
dropfiles_functions.py (the file with the programming logic)
# -*- coding: utf-8 -*-
import os
from PyQt5 import QtCore, QtWidgets
from dropfiles_gui import Ui_MainWindow
class Drop_groupBox(QtWidgets.QGroupBox):
dropped = QtCore.pyqtSignal(list)
def __init__(self, parent):
super().__init__(parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, e):
if e.mimeData().hasUrls():
e.accept()
else:
e.ignore()
def dropEvent(self, e):
list_of_files = [url.toLocalFile() for url in e.mimeData().urls() if os.path.isfile(url.toLocalFile())]
self.dropped.emit(list_of_files)
class MConv(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.groupBox = Drop_groupBox(self.ui.centralwidget) # <-- why is this not working?
self.ui.groupBox.dropped.connect(self.fill_fileslist) # <-- why is this not working?
def fill_fileslist(self, files_list):
self.listWidget_Files.addItems(files_list)
print(files_list)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = MConv()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
I don't understand why the drop event is not passed to the groupBox. In the file 'dropfiles_functions.py' I changed the 'self.ui.groupBox' to the 'new Drop_groupBox', but its funcitonaltiy is not working. Can someone please explain to me why this is the case and what I'm doing wrong?
In order to get this to work, you need to promote your groupbox widget in QtDesigner from a QtWidgets.QGroupBox to a Drop_groupBox widget. You can check the official Qt documentation to find out how. If you succeed and convert the .ui file to a .py file, the line
self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
should have been replaced by
self.groupBox = Drop_groupBox(self.centralwidget)
and at the bottom of the .py file there should be an import statement similar to
from dropfiles_functions import Drop_groupBox
The next step is to correctly setup MConv. Since MConv inherits from both QMainWindow and Ui_MainWindow, you don't need to create a separate instance of Ui_MainWindow in QMainWindow.__init__. Instead you can refer to MConv.setupUi and MConv.groupBox directly, i.e.
class MConv(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__(self)
self.setupUi(self) # <-- this will define self.groupBox = Drop_groupbox(...) amongst others
self.groupBox.dropped.connect(self.fill_fileslist)
def fill_fileslist(self, files_list):
self.listWidget_Files.addItems(files_list)
print(files_list)
Finally, in the if __name__ == "__main__" block you need to make sure you are using an instance of MConv rather than a standard QMainWindow, i.e.
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = MConv()
MainWindow.show()
sys.exit(app.exec_())

Cannot create a successful exe file in python [duplicate]

This question already has answers here:
'google-cloud-firestore' distribution doesn't get added to PyInstaller build
(3 answers)
Closed 3 years ago.
I am using a lot of dependencies for my python project. I am using firestore, pyqt5, numpy and some others. I tried creating an executable file using Pyinstaller but whenever I run the file it says "failed to execute script.
Also I am using images folder and 2 other python file as imports in my main.py file
I tried using hidden imports and still wouldn't work. Is there any easy way to create a pyqt5+firestore project?
Main.py
from PyQt5 import QtWidgets
from HomePage import Ui_HomePage
from attendance import Ui_Dialog
class Firstwindow(QtWidgets.QMainWindow, Ui_HomePage):
def __init__(self, parent=None):
super(Firstwindow, self).__init__(parent)
self.setupUi(self)
self.viewAttendance.clicked.connect(self.hide)
class Secondwindow(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent=None):
super(Secondwindow, self).__init__(parent)
self.setupUi(self)
self.backButton.clicked.connect(self.hide)
class Manager:
def __init__(self):
self.first = Firstwindow()
self.second = Secondwindow()
self.first.viewAttendance.clicked.connect(self.second.show)
self.second.backButton.clicked.connect(self.first.show)
self.first.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
manager = Manager()
sys.exit(app.exec_())
attendance.py
from PyQt5 import QtCore, QtGui, QtWidgets
import firebase_admin
import google.cloud
from firebase_admin import credentials, firestore
cred = credentials.Certificate("******")
app1 = firebase_admin.initialize_app(cred)
"""Creating a database and authorization object"""
DB = firestore.client()
ids = []
names = []
age = []
job = []
phone = []
year = []
date = []
shiftStart = []
shiftEnd = []
store = firestore.client()
peopleRef = store.collection(u'People')
salaryRef = store.collection('Salary')
jobRef = store.collection('Jobs')
recordRef = store.collection('Records')
dates = recordRef.stream()
for dat in dates:
x = store.collection('Records').document(dat.id).collection('Present')
idx = x.stream()
for i in idx:
print(i.id)
print(i.to_dict()['Name'])
jo = jobRef.stream()
for doc in jo:
fo = doc.id
print(fo)
def getData():
try:
docs = peopleRef.stream()
for doc in docs:
ids.append(doc.id)
names.append(doc.to_dict()['Name'])
job.append(doc.to_dict()['Age'])
age.append(doc.to_dict()['Job Type'])
phone.append(doc.to_dict()['Phone'])
except google.cloud.exceptions.NotFound:
print(u'Missing data')
return ids,names,job,age,phone
def clearData():
ids.clear()
names.clear()
age.clear()
job.clear()
phone.clear()
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(595, 337)
Dialog.setWindowFlag(QtCore.Qt.WindowContextHelpButtonHint,False)
self.gridLayout_2 = QtWidgets.QGridLayout(Dialog)
self.gridLayout_2.setObjectName("gridLayout_2")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem, 0, 5, 1, 1)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem1, 0, 3, 1, 1)
self.dateEdit = QtWidgets.QDateEdit(Dialog)
self.dateEdit.setStyleSheet("font: 10pt \"Verdana\";")
self.dateEdit.setObjectName("dateEdit")
self.gridLayout.addWidget(self.dateEdit, 0, 6, 1, 1)
self.refreshButton = QtWidgets.QPushButton(Dialog)
self.refreshButton.setStyleSheet("qproperty-icon:url(:/images/icons/refresh.png);\n"
"background-color: rgb(255, 255, 255);")
self.refreshButton.setText("")
self.refreshButton.setIconSize(QtCore.QSize(20, 20))
self.refreshButton.setFlat(False)
self.refreshButton.setObjectName("refreshButton")
self.gridLayout.addWidget(self.refreshButton, 0, 4, 1, 1)
self.searchDate = QtWidgets.QPushButton(Dialog)
self.searchDate.setStyleSheet("QPushButton {\n"
" color: rgb(0,0,0);\n"
" border: 2px solid #555;\n"
" border-radius: 20px;\n"
" border-style: outset;\n"
" background: rgb(215, 252, 255);\n"
" padding: 5px;\n"
" font: 75 8pt \"Georgia\";\n"
" }\n"
"\n"
"QPushButton:hover {\n"
" background: rgb(111, 210, 255)\n"
" }\n"
"\n"
"QPushButton:pressed {\n"
" border-style: inset;\n"
" background: rgb(111, 210, 255)\n"
" }\n"
"")
self.searchDate.setObjectName("searchDate")
self.gridLayout.addWidget(self.searchDate, 0, 7, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.backButton = QtWidgets.QPushButton(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.backButton.sizePolicy().hasHeightForWidth())
self.backButton.setSizePolicy(sizePolicy)
self.backButton.setStyleSheet("qproperty-icon:url(:/images/icons/back.jpg);\n"
"background-color: rgb(255, 255, 255);")
self.backButton.setText("")
self.backButton.setObjectName("backButton")
self.horizontalLayout.addWidget(self.backButton)
self.nameEntry = QtWidgets.QLineEdit(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.nameEntry.sizePolicy().hasHeightForWidth())
self.nameEntry.setSizePolicy(sizePolicy)
self.nameEntry.setStyleSheet("font: 10pt \"Verdana\";")
self.nameEntry.setObjectName("nameEntry")
self.horizontalLayout.addWidget(self.nameEntry)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.searchName = QtWidgets.QPushButton(Dialog)
self.searchName.setStyleSheet("QPushButton {\n"
" color: rgb(0,0,0);\n"
" border: 2px solid #555;\n"
" border-radius: 20px;\n"
" border-style: outset;\n"
" background: rgb(215, 252, 255);\n"
" padding: 5px;\n"
" font: 75 8pt \"Georgia\";\n"
" }\n"
"\n"
"QPushButton:hover {\n"
" background: rgb(111, 210, 255)\n"
" }\n"
"\n"
"QPushButton:pressed {\n"
" border-style: inset;\n"
" background: rgb(111, 210, 255)\n"
" }\n"
"")
self.searchName.setObjectName("searchName")
self.gridLayout.addWidget(self.searchName, 0, 1, 1, 1)
self.profileTree = QtWidgets.QTableWidget(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.profileTree.sizePolicy().hasHeightForWidth())
self.profileTree.setSizePolicy(sizePolicy)
self.profileTree.setObjectName("profileTree")
self.gridLayout.addWidget(self.profileTree, 1, 0, 1, 1)
self.dataTree = QtWidgets.QTableWidget(Dialog)
self.dataTree.setObjectName("dataTree")
self.gridLayout.addWidget(self.dataTree, 1, 1, 1, 7)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
self.dataTree.setColumnCount(0)
self.dataTree.setRowCount(0)
self.profileTree.setRowCount(0)
self.profileTree.setColumnCount(0)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
self.profileTree.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
self.refreshButton.clicked.connect(self.refresh)
self.profileTree.cellDoubleClicked.connect(self.showClicked)
def showClicked(self,row,col):
idx = self.profileTree.item(row,0).text()
print(idx)
def refresh(self):
profileData = getData()
self.profileTree.setRowCount(len(profileData[0]))
self.profileTree.setColumnCount(2)
self.profileTree.setHorizontalHeaderLabels(('ID', 'Name'))
for row in range(len(profileData[0])):
for col in range(2):
self.profileTree.setItem(row,col,QtWidgets.QTableWidgetItem(profileData[col][row]))
clearData()
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.searchDate.setText(_translate("Dialog", "Search"))
self.searchName.setText(_translate("Dialog", "Search"))
import images
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_())
Ok so after hours of research I found this post - 'google-cloud-firestore' distribution doesn't get added to PyInstaller build
The problem was with firestore and not PyQt.

How to get filepath from droped file with pyqt5?

I want to get path of the file dropped on QLabel. So I code like this, but label doesn't accept the file. What is the problem..?
Here is my code. So long code sorry and thank you!
import random
import sys
import pygame
import time
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QWidget, QLabel, QApplication, QDesktopWidget
class Example(QWidget):
size=100
imgNum=0
frameCount=4
isXmin = False
isXmax = False
isYmin = False
isYmax = False
isLeft= True
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
sizeObject = QDesktopWidget().screenGeometry()
# print(" Screen size : " + str(sizeObject.height()) + "x" + str(sizeObject.width()))
self.xMax=sizeObject.width()-10
self.yMax=sizeObject.height()-10
print(self.xMax)
print(self.yMax)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setStyleSheet("background-color:transparent;")
self.setGeometry(100, 100, 100, 100)
self.setWindowFlags(Qt.SplashScreen | Qt.WindowStaysOnTopHint)
self.setAcceptDrops(True)
self.label=QLabel(self)
self.label.setAcceptDrops(True)
self.pixmaps=[QPixmap('left.png'),QPixmap('stand.png'),QPixmap('right.png'),QPixmap('stand.png'),QPixmap('leftR.png'),QPixmap('standR.png'),QPixmap('rightR.png'),QPixmap('standR.png')]
for x in range(len(self.pixmaps)):
self.pixmaps[x]=self.pixmaps[x].scaled(self.size,self.size,Qt.KeepAspectRatio)
self.resize(self.pixmaps[2].width(),self.pixmaps[2].height())
self.label.setPixmap(self.pixmaps[len(self.pixmaps)-1])
self.changeTimer=QTimer(self)
self.changeTimer.timeout.connect(self.changeFoot)
self.moveTimer=QTimer(self)
self.moveTimer.timeout.connect(self.moving)
self.setAcceptDrops(True)
pygame.init()
pygame.mixer.music.load('hoi_imtemmie.mp3')
pygame.mixer.music.play()
self.show()
def dragEnterEvent(self, event):
if event.mimeData().hasUrls:
event.accept()
else:
event.ingore()
def dropEvent(self, event):
self.path=event.mimeData.urls()
def moving(self):
if self.distance == 0:
print(self.distance)
print(self.x(),"x",self.y())
self.label.setPixmap(self.pixmaps[1])
self.moveTimer.stop()
self.changeTimer.stop()
time.sleep(3)
self.setMovement()
return 0
else:
self.move(self.x()+self.direct[0],self.y()+self.direct[1])
self.distance-=1
if self.x()<=-10 :
self.distance=0
print("xm")
self.isXmin = True
if self.y()<=-10 :
self.distance=0
print("ym")
self.isYmin = True
if self.x()>=self.xMax:
self.distance=0
print("xM")
self.isXmax=True
if self.y()>=self.yMax :
self.distance=0
print("yM")
self.isYmax=True
def setMovement(self):
self.direct=[0,0]
while(self.direct[0]==0 and self.direct[1]==0):
self.direct=[random.randint(-1,1),random.randint(-1,1)]
if self.isXmax:
self.direct[0]=-1
if self.isXmin:
self.direct[0]=1
if self.isYmin:
self.direct[1]=1
if self.isYmax:
self.direct[1]=-1
if self.direct[0]== -1:
self.isLeft=True
self.imgNum=0
elif self.direct[0]== 1:
self.isLeft=False
self.imgNum=4
self.isXmax = False
self.isXmin = False
self.isYmin = False
self.isYmax = False
# if direct[0]*direct[1]==0 : self.delta = QPoint(dX*direct[0],dY*direct[1])
# else: self.delta=QPoint(direct[0]*(dX**(1/2)),direct[1]*(dY**1/2))
self.distance=random.randint(200,400)
self.changeTimer.start(300)
self.moveTimer.start(30)
def changeFoot(self):
self.label.setPixmap(self.pixmaps[self.imgNum])
if self.isLeft:
if self.imgNum<self.frameCount-1:
self.imgNum+=1
else :
self.imgNum=0
else:
if self.imgNum<2*self.frameCount-1:
self.imgNum+=1
else :
self.imgNum=self.frameCount
def mousePressEvent(self, QMouseEvent):
self.setMovement()
pygame.mixer.music.load('hoi_imtemmie.mp3')
pygame.mixer.music.play()
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
sys.exit()
# if QKeyEvent.key() == Qt.Key_G:
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
i set AcceptDrops(True)
self.setAcceptDrops(True)
and code about get filepath ▼
def dragEnterEvent(self, event):
if event.mimeData().hasUrls:
event.accept()
else:
event.ingore()
def dropEvent(self, event):
self.path=event.mimeData.urls()
Try to loop through event.mimeData().urls()
for url in event.mimeData().urls():
self.path = url.toLocalFile()

PySide: Create popup based on location of button and window's edge

I'd like to create a popup at the position of a clicked button and also offset that popup along the left edge of the existing window.
Right now I'm getting the position of the button fine, but it seems that the position of the window is off a little because when the popup is created it's about 200 pixels off to the left. I've commented the relevant sections below in my code. Thanks for any help/critiques.
from PySide import QtCore, QtGui
from shiboken import wrapInstance
def get_parent():
ptr = mui.MQtUtil.mainWindow()
return wrapInstance( long( ptr ), QtGui.QWidget )
############################################
class Tool_Window(QtGui.QDialog):
def __init__(self, parent = get_parent() ):
super(Tool_Window, self).__init__(parent)
self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
# Commands
self.move_UI()
self.create_gui()
self.create_layout()
self.create_connections()
#-------------------------------------------
def create_gui(self):
self.button1 = QtGui.QPushButton()
self.button1.setMaximumWidth(50)
self.button2 = QtGui.QPushButton()
self.button2.setMaximumWidth(50)
self.button3 = QtGui.QPushButton()
self.button3.setMaximumWidth(50)
#-------------------------------------------
def create_layout(self):
layout = QtGui.QVBoxLayout()
layout.addWidget(self.button1)
layout.addWidget(self.button2)
layout.addWidget(self.button3)
layout.addStretch()
self.setLayout(layout)
#-------------------------------------------
def move_UI( self ):
''' Moves the UI to the cursor's position '''
pos = QtGui.QCursor.pos()
self.move(pos.x()+20, pos.y()+15)
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
def create_connections(self):
# Left click
self.button1.clicked.connect( self.on_left_click1 )
self.button2.clicked.connect( self.on_left_click2 )
self.button3.clicked.connect( self.on_left_click3 )
# Right click delete
delete = QtGui.QAction(self)
delete.setText("remove")
delete.triggered.connect(self.remove_button)
self.addAction(delete)
#-----#-----#-----#-----#-----#-----#-----#-----#-----#
def remove_button(self):
self.deleteLater()
def on_left_click1(self):
self.popup = Popup_Window(self, self.button1 ) # Passing button in so I can get it's position
self.popup.show()
def on_left_click2(self):
self.popup = Popup_Window(self, self.button2 )
self.popup.show()
def on_left_click3(self):
self.popup = Popup_Window(self, self.button3 )
self.popup.show()
############################################
class Popup_Window( QtGui.QDialog ):
def __init__( self, toolWindow, button ):
super( Popup_Window, self ).__init__()
self.button_pos = button # Creating variable for the button
self.toolWindow= mainUIWindow
self.setAttribute( QtCore.Qt.WA_DeleteOnClose )
#self.setMinimumWidth(100) # I need a minimum width
# Commands
self.create_gui()
self.create_layout()
self.create_connections()
self.move_UI()
#-------------------------------------------
def move_UI( self ): # Move popup based on pos of window and buttons
''' Moves the UI to the cursor's position '''
self.setWindowFlags(QtCore.Qt.Popup)
self.line_edit.setFocus()
# Get button position
btn_global_point = self.button_pos.mapToGlobal(self.button_pos.rect().topLeft())
# Get window position
win_global_point = self.mapToGlobal(self.rect().topLeft())
self.move(btn_global_point - win_global_point) # Here is where I find the distance between the window edge and button edge
#-------------------------------------------
def create_gui( self ):
''' Visible GUI stuff '''
self.my_label = QtGui.QLabel("default text")
self.line_edit = QtGui.QLineEdit()
self.line_edit.setMaxLength( 30 )
self.push_btn = QtGui.QPushButton( "Hey" )
self.push_btn.setMaximumWidth( 30 )
#-------------------------------------------
def create_layout( self ):
self.button_layout = QtGui.QVBoxLayout()
self.button_layout.addWidget( self.my_label )
self.button_layout.addWidget( self.line_edit )
self.button_layout.addWidget( self.push_btn )
self.setLayout(self.button_layout)
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
def create_connections( self ):
self.line_edit.textChanged.connect( self.on_text_changed )
#-----#-----#-----#-----#-----#-----#-----#-----#-----#
def on_text_changed( self ):
typed_name = self.line_edit.text()
self.my_label.setText(typed_name)
if __name__ == '__main__':
# Things to fix PySide Maya bug
try:
test_ui.close()
test_ui.deleteLater()
except:
pass
test_ui = Tool_Window()
test_ui.show()
try:
test_ui.show()
except:
test_ui.close()
test_ui.deleteLater()
Solution:
# Get button position
btn_global_point = self.button_pos.mapToGlobal(self.button_pos.rect().topLeft())
# Get window position
win_global_point = self.toolWindow.mapToGlobal(self.rect().topLeft())
self.move(win_global_point.x(), btn_global_point.y())
If I understand what you want to achieve, you have to keep only the y-value of button position and the x-value of window position.
So try this code:
# Get y button position
btn_global_point_y = self.button_pos.mapToGlobal(self.button_pos.rect().topLeft()).y()
# Get window position
win_global_point_x = self.mapToGlobal(self.rect().topLeft()).x()
self.move(win_global_point_x, btn_global_point_y)
With this lines you move the popup window at the height of the button and snap it to the left edge of the window.