can't access class variable python - python

I'm building a desktop app with python and have some issues getting a class variable I set up.
My program is built like this:
CharCreator.py
class MainWindow(QtWidgets.QMainWindow):
charName = ""
def __init__(self):
super().__init__()
def editCharClick(self):
from CharEdit import editUi
MainWindow.charName = self.getSelected()
print(MainWindow.charName)
if(MainWindow.charName is not None):
self.editWin = editUi()
self.editWin.show()
else:
print("charName is none")
def main():
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
So I've got my main window class, with a charName class variable.
Then I have the typical methods(init, main etc) and have an editCharClick method that takes the selected row of my table, gets the name of my desired cell and assigns its string content to my class variable.
This part works well in my CharCreator.py file.
The problem comes in my second file. As seen in my editCharClick method, it opens a second window (CharEdit.py file). That's where I need to get the MainWindow.charName class variable.
CharEdit.py
class editUi(QtWidgets.QMainWindow):
def __init__(self):
super(editUi, self).__init__()
uic.loadUi("./ui/new.ui", self)
from CharCreator import MainWindow
print(MainWindow.charName)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
newwindow = editUi()
sys.exit(app.exec_())
I've simplified this file just to get my class variable right, yet can't seem to make it happen.
Any help would be appreciated, thanks.

I tried changing my code to work with event/signals but didn't quite like it.
So I just went the easy way and changed the editUi class constructor so it would accept another argument.
Then, when creating the editUi object in MainWindow.editCharClick(), you can pass the variable in the editUi object as an argument.
CharCreator.py
class MainWindow(QtWidgets.QMainWindow):
charName = ""
def __init__(self):
super().__init__()
def editCharClick(self):
from CharEdit import editUi
MainWindow.charName = self.getSelected()
print(MainWindow.charName)
if(MainWindow.charName is not None):
self.editWin = editUi(MainWindow.charName)
self.editWin.show()
else:
print("charName is none")
def main():
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
CharEdit.py
class editUi(QtWidgets.QMainWindow):
def __init__(self, ch):
super(editUi, self).__init__()
uic.loadUi("./ui/new.ui", self)
from CharCreator import MainWindow
print(ch)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
newwindow = editUi()
sys.exit(app.exec_())

Related

How to prevent PyQt Line Edit and Message Box from being stuck in an infinite loop?

In the code below, after any sort of editing or completion in the line edit box, the modify function will be called. Then, the program will be stuck in an infinite loop, resulting in continuous QMessageBox pop-ups and 'modifying..' print statements, followed by the eventual crash of the program.
I've tried to put self.win.processEvents() at different places, but it doesn't help.
from PyQt5 import QtWidgets
class Test:
def __init__(self):
self.app = QtWidgets.QApplication([])
self.win = QtWidgets.QMainWindow()
self.le_dwell_filter = QtWidgets.QLineEdit()
self.le_dwell_filter.editingFinished.connect(self.modify)
self.win.setCentralWidget(self.le_dwell_filter)
self.win.show()
def modify(self):
print('Modifying...')
msgbox = QtWidgets.QMessageBox()
msgbox.setText('modification done!')
msgbox.show()
def start(self):
self.app.exec()
if __name__ == '__main__':
my_test = Test()
my_test.start()
I would have thought this will print one 'Modifying...', but somehow QMessageBox keeps popping up and the printing keeps happening.. I think it has to do with PyQt Event loop?
You want to have a single QMessageBox so why do you create a new QMessageBox in the modify method ?, what you have to do is reuse:
class Test:
def __init__(self):
self.app = QtWidgets.QApplication([])
self.win = QtWidgets.QMainWindow()
self.le_dwell_filter = QtWidgets.QLineEdit()
self.le_dwell_filter.editingFinished.connect(self.modify)
self.win.setCentralWidget(self.le_dwell_filter)
self.win.show()
self.msgbox = QtWidgets.QMessageBox()
def modify(self):
print('Modifying...')
self.msgbox.setText('modification done!')
self.msgbox.show()
def start(self):
self.app.exec()

How to process data after reading from QIODevice.read()?

This is my first time to ask question, if there are something I get wrong, please tell me, I will be appreciate.
I am using QWebEngineUrlSchemeHandler for a custom url, and I want to use QFile to open a javascript file for testing.
First, if I just use
QFile("ken.js")
The window could open the javascript, but if I use my custom QFile,
I have no idea how to process the data after I read from QIODevice.read().
I want to know what I need to do to make the window could open the javascript after I read the data from QIODevice.read().
Please give me some suggests, thank.
Here is my full code.
class TestQFile(QtCore.QFile):
def __init__(self, fileName):
super().__init__()
self.setFileName(fileName)
self.open(self.ReadOnly)
self.data = b''
while True:
receivedData = self.read(10)
self.data += receivedData
if receivedData == b'':
break
class TestHandler(QWebEngineUrlSchemeHandler):
def requestStarted(self, request):
self._dev = TestQFile("ken.js")
request.reply(b'text/javascript', self._dev)
class TestWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._view = QWebEngineView(self)
self._handler = TestHandler() # Must keep ref
self._view.page().profile().installUrlSchemeHandler(b'myuri', self._handler)
self._view.setHtml('<html><head><title>Test</title></head><body><div id="d1"></div><script src="myuri://test/ken.js"></script></body></html>')
self.setCentralWidget(self._view)
self.show()
self.raise_()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
win = TestWindow()
app.exec_()
Actually if the class inherits from QFile you do not have to do anything since it already has implemented the methods that QWebEngineUrlRequestJob requires since it will use the methods that every class that inherits from QIODevice must implement as readData(), writeData(), atEnd(), etc.
from PyQt5 import QtCore, QtWidgets, QtWebEngineCore,QtWebEngineWidgets
class TestQFile(QtCore.QFile):
def __init__(self, fileName):
super().__init__()
self.setFileName(fileName)
class TestHandler(QtWebEngineCore.QWebEngineUrlSchemeHandler):
def requestStarted(self, request):
self.file = TestQFile("ken.js")
request.reply(b'text/javascript', self.file)
class TestWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._view = QtWebEngineWidgets.QWebEngineView(self)
self._handler = TestHandler() # Must keep ref
self._view.page().profile().installUrlSchemeHandler(b'myuri', self._handler)
self._view.setHtml('<html><head><title>Test</title></head><body><div id="d1"></div><script src="myuri://test/ken.js"></script></body></html>')
self.setCentralWidget(self._view)
self.show()
self.raise_()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
win = TestWindow()
sys.exit(app.exec_())

Return value from PYQt slot of QwebView to main window widget (PYQt python)

i am building a desktop application using PyQt python which has a QwebBrowser. now i am running some function using javascript which is returning a value say abc as per following example.
class QWebView(QWebView):
def contextMenuEvent(self,event):
menu = QMenu()
self.actionShowXpath = menu.addAction("Show Xpath")
QObject.connect(self.actionShowXpath,SIGNAL("triggered()"),self,SLOT("slotshowxpath()"))
menu.exec_(self.mapToGlobal(QPoint(event.x(),event.y())))
#pyqtSlot()
def slotshowxpath(self):
frame.evaluateJavaScript("var abc = function get()");
result = frame.evaluateJavaScript("abc").toString()
**some code code to put result in QLineEdit Widget**
# something like below
# xpath.setText(result)
def window():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
web = QWebView(w)
web.load(QUrl("http://www.indiatimes.com/"))
web.show()
xpath = QtGui.QLineEdit("", w)
sys.exit(app.exec_())
if __name__ == '__main__':
window()
now, i want to put the value of abc in a QLineEdit widget("xpath") present in my application.please give me suggestion that how i can i do this?
I can't work up an example because QtWebkit has been removed from Qt 5.6, but if the problem you are having is because you don't have a reference to your QLineEdit, then pass the QLineEdit to your QWebView class's __init__() function:
def start_app():
app = QtGui.QApplication(sys.argv)
main_window = QtGui.QWidget()
xpathInput = QtGui.QLineEdit(main_window)
web_view = MyWebView(main_window, xpathInput) #<===HERE
web_view.load(QUrl("http://www.indiatimes.com/"))
main_window.show()
sys.exit(app.exec_())
Then in your QWebView class:
class MyWebView(QWebView):
def __init__(self, parent, xpath_widget):
#QWebView.__init__(parent)
QWebView.__init__(self, parent)
#or: super(MyWebView, self).__init__(parent)
self.xpath_widget = xpath_widget
def contextMenuEvent(self,event):
menu = QMenu()
self.actionShowXpath = menu.addAction("Show Xpath")
#QObject.connect(
# self.actionShowXpath,
# SIGNAL("triggered()"),
# self,SLOT("slotshowxpath()")
#)
self.actionShowXpath.triggered.connect(self.show_xpath)
menu.exec_(self.mapToGlobal(QPoint(event.x(),event.y())))
##pyqtSlot()
def show_xpath(self):
frame = ...
frame.evaluateJavaScript("var abc = function get()");
result = frame.evaluateJavaScript("abc").toString()
#some code code to put result in QLineEdit Widget**
self.xpath_widget.setText(result)
But I think a better way to organize your code would be to do something like this:
class MyWindow(QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.xpathInput = QtGui.QLineEdit(self)
self.web_view = QWebView(self)
self.web_view.load(QUrl("http://www.indiatimes.com/"))
self.menu = QMenu()
self.actionShowXpath = self.menu.addAction("Show Xpath")
#QObject.connect(
# self.actionShowXpath,
# SIGNAL("triggered()"),
# self,SLOT("slotshowxpath()")
#)
self.actionShowXpath.triggered.connect(self.show_xpath)
menu.exec_(self.mapToGlobal(QPoint(event.x(),event.y())))
def show_path(self):
frame = ...
result = frame.evaluateJavaScript("abc").toString()
self.xpathInput.setText(result)
def start_app():
app = QtGui.QApplication(sys.argv)
main_window = MyWindow()
main_window.show()
sys.exit(app.exec_())

How to access attribute of the main window

I am writing a program and I want for external function to access attribute of the main window. It must be an external function, because it is provided by import method. I have created a really small MWE to give an idea of the problem. Here function func is supposed to print value of MainWindow's vari.
class importedclass():
def func(self):
print(win.vari)
x=importedclass()
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.vari = 1
x.func()
def main():
app = QtGui.QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Just to make it clear: importedclass class is my fix-up class, I am not allowed to change anything in MainWindow class!
Because each one needs an instance of the other, one of them needs to pass itself to the other. Check if this example solution fully addresses your problem.
# file 1
class External():
def func(self, win):
print(win.vari)
# file 2
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.vari = 1
import External
x = External()
x.func(self)
def main():
app = QtGui.QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())

Python: PyQt QTreeview example - selection

I'm using Python 2.7 and Qt designer and I'm new to MVC:
I have a View completed within Qt to give me a directory tree list, and the controller in place to run things. My question is:
Given a Qtree view, how may I obtain a directory once a dir is selected?
Code snap shot is below, I suspect it's SIGNAL(..) though I'm unsure:
class Main(QtGui.QMainWindow):
plot = pyqtSignal()
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# create model
model = QtGui.QFileSystemModel()
model.setRootPath( QtCore.QDir.currentPath() )
# set the model
self.ui.treeView.setModel(model)
**QtCore.QObject.connect(self.ui.treeView, QtCore.SIGNAL('clicked()'), self.test)**
def test(self):
print "hello!"
The signal you're looking for is selectionChanged emmited by the selectionModel owned by your tree. This signal is emmited with the selected item as first argument and the deselected as second, both are instances of QItemSelection.
So you might want to change the line:
QtCore.QObject.connect(self.ui.treeView, QtCore.SIGNAL('clicked()'), self.test)
to
QtCore.QObject.connect(self.ui.treeView.selectionModel(), QtCore.SIGNAL('selectionChanged()'), self.test)
Also I recommend you to use the new style for signals and slots. Redefine your test function as:
#QtCore.pyqtSlot("QItemSelection, QItemSelection")
def test(self, selected, deselected):
print("hello!")
print(selected)
print(deselected)
Here you have a working example:
from PyQt4 import QtGui
from PyQt4 import QtCore
class Main(QtGui.QTreeView):
def __init__(self):
QtGui.QTreeView.__init__(self)
model = QtGui.QFileSystemModel()
model.setRootPath( QtCore.QDir.currentPath() )
self.setModel(model)
QtCore.QObject.connect(self.selectionModel(), QtCore.SIGNAL('selectionChanged(QItemSelection, QItemSelection)'), self.test)
#QtCore.pyqtSlot("QItemSelection, QItemSelection")
def test(self, selected, deselected):
print("hello!")
print(selected)
print(deselected)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = Main()
w.show()
sys.exit(app.exec_())
PyQt5
In PyQt5 is a little bit different (thanks to Carel and saldenisov for comments and aswer.)
... connect moved from being an object method to a method acting upon the attribute when PyQt went from 4 to 5
So instead the known:
QtCore.QObject.connect(self.ui.treeView, QtCore.SIGNAL('clicked()'), self.test)
now you write:
class Main(QTreeView):
def __init__(self):
# ...
self.setModel(model)
self.doubleClicked.connect(self.test) # Note that the the signal is now a attribute of the widget.
Here is a the example (by saldenisov) using PyQt5.
from PyQt5.QtWidgets import QTreeView,QFileSystemModel,QApplication
class Main(QTreeView):
def __init__(self):
QTreeView.__init__(self)
model = QFileSystemModel()
model.setRootPath('C:\\')
self.setModel(model)
self.doubleClicked.connect(self.test)
def test(self, signal):
file_path=self.model().filePath(signal)
print(file_path)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Main()
w.show()
sys.exit(app.exec_())
In PyQt5 it can be done in this way:
from PyQt5.QtWidgets import QTreeView,QFileSystemModel,QApplication
class Main(QTreeView):
def __init__(self):
QTreeView.__init__(self)
model = QFileSystemModel()
model.setRootPath('C:\\')
self.setModel(model)
self.doubleClicked.connect(self.test)
def test(self, signal):
file_path=self.model().filePath(signal)
print(file_path)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Main()
w.show()
sys.exit(app.exec_())
If I understand the question correctly you would like the directory or file name selected.
This is what I do:
from PyQt4 import QtGui
from PyQt4 import QtCore
# ---------------------------------------------------------------------
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(600,400)
self.setWindowTitle("Treeview Example")
self.treeview = QtGui.QTreeView(self)
self.treeview.model = QtGui.QFileSystemModel()
self.treeview.model.setRootPath( QtCore.QDir.currentPath() )
self.treeview.setModel(self.treeview.model)
self.treeview.setColumnWidth(0, 200)
self.setCentralWidget(self.treeview)
self.treeview.clicked.connect(self.on_treeview_clicked)
# ---------------------------------------------------------------------
#QtCore.pyqtSlot(QtCore.QModelIndex)
def on_treeview_clicked(self, index):
indexItem = self.treeview.model.index(index.row(), 0, index.parent())
# path or filename selected
fileName = self.treeview.model.fileName(indexItem)
# full path/filename selected
filePath = self.treeview.model.filePath(indexItem)
print(fileName)
print(filePath)
# ---------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
I tried this alternative to get the file name...
Instead of:
indexItem = self.treeview.model.index(index.row(), 0, index.parent())
# path or filename selected
fileName = self.treeview.model.fileName(indexItem)
I tried:
# path or filename selected
fileName = index.internalPointer().fileName
Which also seems to work...

Categories

Resources