Reverting imported dictionary via QPushButton issues - python-3.x

I am having trouble understanding why a deep copy of a dictionary reverts back to original values when I run the revert() method once, but when I change values again, and run the revert() method again it changes the copied dictionaries values along with the original.
The dictionary/values are being imported from another file. I can only assume it is because the Test is being imported more than once.
Can someone help explain why this is happening and what can I do to avoid it?
Test.py
import ujson,copy
nested1 = {'1':None, '2':"String"}
nested2 = {'1':0.5123, '2':515}
diction = {'1':nested1, '2':nested2}
copyDiction = ujson.loads(ujson.dumps(diction))
copyOtherDiction = copy.deepcopy(diction)
Main.py
import Test
from PyQt5 import QtCore, QtWidgets, QtGui
class Window(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super(Window,self).__init__(parent)
widget = QtWidgets.QWidget()
self.setCentralWidget(widget)
layout = QtWidgets.QVBoxLayout()
self.lineEdit = QtWidgets.QLineEdit()
self.button = QtWidgets.QPushButton("Change Value")
self.button.clicked.connect(self.changeMethod)
self.revertbutton = QtWidgets.QPushButton("Revert")
self.revertbutton.clicked.connect(self.revert)
layout.addWidget(self.lineEdit)
layout.addWidget(self.button)
layout.addWidget(self.revertbutton)
widget.setLayout(layout)
def changeMethod(self):
text = self.lineEdit.text()
if text.isdigit():
Test.diction['1']['2'] = int(text)
else:
Test.diction['1']['2'] = text
def revert(self):
print(Test.diction)
Test.diction = Test.copyDiction
print(Test.diction)
print(Test.copyDiction)
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Related

PySide2 works not efficient

from PySide2.QtWidgets import QApplication, QMainWindow,QDialog,QLineEdit,QPushButton
from PySide2.QtCore import Qt
import sys
from ui618 import Ui_MainWindow
from numpad import Ui_Dialog
class MyWindow:
def __init__(self) -> None:
self.lastSelectedEditLine = None
# main ui
self.MainWindow = QMainWindow()
self.ui = Ui_MainWindow()
self.ui.setupUi(self.MainWindow)
# numpad
self.QDialog = QDialog(self.MainWindow)
self.numpad = Ui_Dialog()
self.numpad.setupUi(self.QDialog)
self.QDialog.setWindowFlags(Qt.Popup)
# bind editline with numpad
self.lineEdits = self.MainWindow.findChildren(QLineEdit)
for item in self.lineEdits:
item.focusInEvent = lambda e,item=item:self.test(e,item)
def save_quit(self):
sys.exit()
def bindbtn(self):
self.ui.quit.clicked.connect(self.save_quit)
def numpad_btn(self,a,item):
if item.text() != '←':
self.lastSelectedEditLine.setText(self.lastSelectedEditLine.text()+item.text())
else:
self.lastSelectedEditLine.setText(self.lastSelectedEditLine.text()[:-1])
def bindNumpad(self):
numpad_btns = self.QDialog.findChildren(QPushButton)
for item in numpad_btns:
item.clicked.connect(lambda ignore='ignore',item=item : self.numpad_btn(ignore,item))
def test(self,e,item):
self.lastSelectedEditLine = item
this = item
x = self.MainWindow.x()
y = self.MainWindow.y() + self.ui.selectX.rect().bottom()
while this.parentWidget().objectName() != 'MainWindow':
x += this.x()
y += this.y()
this = this.parentWidget()
self.QDialog.move(x, y)
self.QDialog.show()
item.clearFocus()
def show(self):
self.MainWindow.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
myWindow = MyWindow()
myWindow.show()
myWindow.bindbtn()
myWindow.bindNumpad()
sys.exit(app.exec_())
The code works as expected, the numpad shows while focusing in a qlineedit. and can write and delete to target input line.
I am new to pyside2. Is there a better way to implement the numpad? I this way, the cursor is disable, I have to edit at the end of each editline.
It take several seconds while starting, Some one know how to improve it?

Reloading a PyQt5 App without Restarting it first

I have created an app and on one of the Windows (CreateProjectWindow(QDialog)) I complete a form which I then submit using self.buttonBox.accepted.connect(self.getInfo).
On submission, I want the self.tableComboBox in UpdateProjecWindow(QDialog) automatically and immediately updated without me having to first restart the application. The last four lines of code in CreateProjectWindow(QDialog) is all I have tried but none of them works. Below is snippet of the code:
from __future__ import print_function
from datetime import date
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
import os
import subprocess
import pandas as pd
import time
Class CreateProjectWindow(QDialog):
def __init__(self):
super(CreateProjectWindow, self).__init__()
self.setWindowTitle("Create a new project")
self.setGeometry(100, 100, 300, 400)
self.timeStampLineEdit = QDateTime.currentDateTime().toString('MM-dd-yyyy hh:mm:ss')
self.surnameLineEdit = QLineEdit()
self.firstnameLineEdit = QLineEdit()
self.dateOfBirthLineEdit = QDateEdit(calendarPopup=True, displayFormat='MM-dd-yyyy')
self.createForm()
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.buttonBox.accepted.connect(self.getInfo)
self.buttonBox.rejected.connect(self.reject)
def getInfo():
output = {'timestamp': self.timeStampLineEdit,\
'surname' : self.surnameLineEdit,\
'firstname' : self.firstnameLineEdit,\
'dob' : self.dateOfBirthLineEdit}
df = pd.DataFrame(output, index=[0])
df.to_excel('to/some/local/path/profiles_data.xlsx')
return None
QApplication.processEvents() # attempt 1 but doesn't work
QApplication(sys.argv).reload() # attempt 2 but doesn't work
subprocess.Popen([sys.executable, FILEPATH]) # attempt 3 restarts the app which I don't want
os.execl(sys.executable, sys.executable, * sys.argv) # attempt 4 restarts the app which I don't want.
def creatForm(self):
layout = QFormLayout()
layout.addRow(QLabel("Surname"), self.surnameLineEdit)
layout.addRow(QLabel("First Name"), self.firstnameLineEdit)
layout.addRow(QLabel("D.O.B"), self.dateOfBirthLineEdit)
self.formGroupBox.setLayout(layout)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(self.buttonBox)
self.setLayout(mainLayout)
class UpdateProjectWindow(QDialog):
def __init__(self):
super(UpdateProjectWindow, self).__init__()
self.setWindowTitle("Parameter Inputs")
self.setGeometry(100, 100, 300, 400)
self.formGroupBox = QGroupBox("Some Window")
self.tableComboBox = QComboBox()
df = pd.read_excel('to/some/local/path/profiles_data.xlsx')
names = df['surname']
self.tableComboBox.addItems(names)
createForm()
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.buttonBox.accepted.connect(self.processInfo)
self.buttonBox.rejected.connect(self.reject)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(self.buttonBox)
self.setLayout(mainLayout)
def processInfo(self):
get_name = self.tableComboBox.currentText()
print(get_name)
def createForm(self):
layout = QFormLayout()
layout.addRow(QLabel("Select Surname"), self.tableComboBox)
self.formGroupBox.setLayout(layout)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# setting window title
self.setWindowTitle("MyApp")
# setting geometry to the window
self.setGeometry(200, 200, 400, 10)
self.window1 = CreateProjectWindow()
self.window2 = UpdateProjectWindow()
l = QVBoxLayout()
button1 = QPushButton("Create a Project")
button1.clicked.connect(
lambda checked: self.toggle_window(self.window1)
)
l.addWidget(button1)
button2 = QPushButton("Update a Project")
button2.clicked.connect(
lambda checked: self.toggle_window(self.window2)
)
l.addWidget(button2)
w = QWidget()
w.setLayout(l)
self.setCentralWidget(w)
def toggle_window(self, window):
if window.isVisible():
window.hide()
else:
window.show()
if __name__=="__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
There is normally no need to restart a Qt application, and certainly this is not required for your case: restarting the QApplication is almost like closing the program and opening it again, doing that just to update some data doesn't make any sense at all.
A possible solution is to create a custom signal for the first window class, which will be emitted when the database is updated, then connect that signal to a function in the other window that loads the data (which means that that function will also be called at the beginning).
class CreateProjectWindow(QDialog):
dataChanged = pyqtSignal()
# ...
def getInfo(self):
# note that your original data was completely wrong, as you tried to add
# the *widgets* to the frame, while you need to add their *values*
output = {'timestamp': self.timeStampLineEdit,
'surname' : self.surnameLineEdit.text(),
'firstname' : self.firstnameLineEdit.text(),
'dob' : self.dateOfBirthLineEdit.date().toString()}
df = pd.DataFrame(output, index=[0])
df.to_excel('to/some/local/path/profiles_data.xlsx')
self.dataChanged.emit()
self.accept()
class UpdateProjectWindow(QDialog):
def __init__(self):
# ...
self.tableComboBox = QComboBox()
self.updateData()
self.createForm()
# ...
def updateData(self):
self.tableComboBox.clear()
df = pd.read_excel('to/some/local/path/profiles_data.xlsx')
names = df['surname']
self.tableComboBox.addItems(names)
class MainWindow(QMainWindow):
def __init__(self):
# ...
self.window1.dataChanged.connect(self.window2.updateData)
Besides that, you must be much more careful with your code: I spent more time to correct your syntax and bugs than to actually give you this answer. Note that there are various other problems with your example, but I will not address them here as it's off topic. In essence, you must put more attention when writing programs.

Converting bytes to an image with base64 via PyQt5

I've converted a png file like this with base64
b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAangAAGp4B8NQjJQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANRSURB\nVGiB7dpPqFVVFMfxz3tKVGS97EEGGYSZORGKJxHUw/4QgeNoVDTMAiuhoSAIgaD9/wMNhBo0qCZN\nghpIf0ZiDeRFFBJBEpFWgqG+euptsN957Hc853ruOeteL+IPFhzOvay1v/vss/beax+uaLw0Eezv\nGmzGpkWbKv1+AnM4jG9xJjh+J92CF/A15tFraPP4Cs9jzchbnelOfICzmje+zs7ifdwxSoDr8RoW\nAgDKtoB9WDVsiEfw2xAAynYUDw4LYhfOjQCisHPYGQkwgTdGCFC2VwVl13cvIURh73SFeGkMIAp7\nsS3EFjGp9TiexlrciifxRws/C3hgUIgbxGSnf3FPhf9N0qw+qL+jUvpvrDcDIHr4tE+MT1r6fKUp\nxAYxQ6onJYo6vd7S5wLWNQHZHwTRw/dYWRFjhbRwbOv3vYtBTEvjOgqkJ/V8DrMCezv6nMfqfiDb\ngyEKm8Nb0rvX5Unk9mw/kG+GBDIM+zJveD71r8Lfqsf0OOo/aXidYnmjN4uDOIID+FWak+7CY7gq\nyL9FXzPS5myZntPtUR+TcvzdNYE34OeOMcq2rSpQ27xe2DM1ALnuDQZZmhwnsyA3NWhIPz0hvWM9\n/ODCwgMcxO8d4+SaLi5ykOs6Ot2CGxevN0q9X6V/OsbJtbQlzkGiS0OnKu5N4ObAGEttzkEie+q8\nNLzKuk3KYlE6WVzkIH8FBpiT3peyZgNjwJ/FRQ7yU2CAz2rubw2MQdbmHOTHwACfV9ybxMOBMahp\n87UGK3nW2QnVK4T7AnzndgZXF87zJ3Iahxr2RD8dkDZmZT0a4DvXQanjsRwEPg4I8EXN/YcCfOf6\nqN+PERurmQq/k9ITjxpWF91Y0X2rO32hS9OBED0Ntrp0Lz5UlWtWSqvj4j/nta8jNy4+0K0cVJdi\n1+IpaXG5UftjicblILoV6A7rf74xJVX22/geuEBHt5LpL9KR2qw0DNbjcXyoXYWxGFIDl0wLXRZF\n7EIvjwHE7q4QpDX/vksIsUfwXmmH4RyA9nsntkcC5Jo1usPQ+4cFUeiyOJ7OtU46NmibTnM7jbdx\n+ygBypqSCsptP+HYprp0NJCG8VHNjFQiXS+tUIuZ+KRUFzgi7ey+M2Yf1VxRpP4H+dEoOtaum3IA\nAAAASUVORK5CYII=\n'
I have a GUİ to convert this code to and image again but when I enter it and take it with .toPlainText() it turns nothing.
It works if I manually type in the script:
How can I define a variable to fix that?
The problem is that toPlainTex() returns a string that in reality must be a bytearray, a way to convert it is using ast.literal() as I show below:
import ast
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
lay = QtWidgets.QVBoxLayout(self)
self.textEdit = QtWidgets.QTextEdit()
self.label = QtWidgets.QLabel()
self.label.setAlignment(QtCore.Qt.AlignCenter)
button = QtWidgets.QPushButton("convert")
lay.addWidget(self.textEdit)
lay.addWidget(button)
lay.addWidget(self.label)
button.clicked.connect(self.on_clicked)
def on_clicked(self):
text = self.textEdit.toPlainText()
try:
data = ast.literal_eval(text)
ba = QtCore.QByteArray.fromBase64(data)
pixmap = QtGui.QPixmap()
if pixmap.loadFromData(ba, "PNG"):
self.label.setPixmap(pixmap)
except SyntaxError:
pass
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

populating combo box with folders on disk using QFileSystemModel

Hi I have written this basic code trying to populate folders underneath the /Users/ directory, but I don't know what I am missing its not populating.
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
class MyWindow(QtGui.QWidget):
"""docstring for MyWindow"""
def __init__(self, parent=None):
super(MyWindow, self).__init__()
self.setup()
def setup(self):
fsm = QtGui.QFileSystemModel()
fsm.setRootPath("/Users/")
layout = QtGui.QVBoxLayout()
combo = QtGui.QComboBox()
combo.setModel(fsm)
layout.addWidget(combo)
self.setLayout(layout)
def main():
app = QtGui.QApplication(sys.argv)
win = MyWindow()
win.show()
win.raise_()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I am getting a / in the comobobox instead of the whole list of folders under /Users/ directory.
I think its better to use QFileSystemModel instead of using os.listdir interms of efficiency and will update the view if somebody updates folder or adds folder in the /Users/ directory !
Remember that QFileSystemModel is a hierarchical model, so you need to let the QComboBox know which QModelIndex represents the children you want to display. You do that with QComboBox.setRootModelIndex()
QFileSystemModel.setRootPath() conveniently returns the QModelIndex of the path you set.
So a small change is all you need (tested on Windows) -
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
class MyWindow(QtGui.QWidget):
"""docstring for MyWindow"""
def __init__(self, parent=None):
super(MyWindow, self).__init__()
self.setup()
def setup(self):
fsm = QtGui.QFileSystemModel()
index = fsm.setRootPath("/Users/")
layout = QtGui.QVBoxLayout()
combo = QtGui.QComboBox()
combo.setModel(fsm)
combo.setRootModelIndex(index)
layout.addWidget(combo)
self.setLayout(layout)
def main():
app = QtGui.QApplication(sys.argv)
win = MyWindow()
win.show()
win.raise_()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

get all the data treeview?

I need to get all the rows in an array.
As it is, this code returns all the data from the treeview and all the items in array from the treeview. I don't think I have the correct method; how can I fix this?
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.model = QtGui.QStandardItemModel()
self.view = QtGui.QTreeView()
#self.view.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.view.setModel(self.model)
self.setCentralWidget(self.view)
#parent = self.model.invisibleRootItem()
self.model.setHorizontalHeaderLabels(["Referencia","Nombre","Costo","UND","Precio"])
for item in '1234 name 9999 10000'.split():
self.model.appendRow([QtGui.QStandardItem(item),QtGui.QStandardItem(item),QtGui.QStandardItem(item),
QtGui.QStandardItem(item),QtGui.QStandardItem(item),
])
#self.view.setColumnWidth(0,50)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
model = tableView.model()
data = []
for row in range(model.rowCount()):
data.append([])
for column in range(model.columnCount()):
index = model.index(row, column)
data[row].append(str(model.data(index).toString()))

Resources