My problem is that when I'm using Spyder, code that was working fine before I had to re-install Spyder now requires me to re-start Spyder (quitting Python x,y, too) every time I run it.
I thought I had this solved yesterday, but for some reason today my problem has returned.
Someone suggested this answer yesterday, and it worked...momentarily.
I have tried:
import sys
from PyQt4 import QtGui
class CompiledWindow(QtGui.QWidget):
def __init__(self, parent = None):
......
cw = CompiledWindow()
cw.show()
The error I get is:
QWidget: Must construct a QApplication before a QPaintDevice
Then I went back to this (same as before the dots)
app = QtGui.QApplication(sys.argv)
cw = CompiledWindow()
cw.show()
Now it runs fine the FIRST time I run it and the second time, I get the same error as before. The third time, it tells me I don't have a shell selected.
I really don't fundamentally understand what it's complaining about. If I must construct a QApplication before a QPaintDevice, why does it run OK the first time? Clearly, it's happening the first time. Why do subsequent runs give me errors? Also, When I got rid of the app part as suggested in the linked answer, it worked...until this morning.
ETA This is a minimal working example as requested. Thanks!
import sys
from PyQt4 import QtGui
class CompiledWindow(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle('Enter data below to generate report')
names = ['Name Report', 'Open Logo Picture']
grid = QtGui.QGridLayout(self)
self.report_title_ask = QtGui.QLineEdit()
self.rt = QtGui.QLabel()
self.rt.setText(names[0])
grid.addWidget(self.report_title_ask, 0, 1)
grid.addWidget(self.rt, 0, 0)
self.Logo_button = QtGui.QPushButton(names[1], self)
self.LogoLabel = QtGui.QLabel()
self.Logo_button.clicked.connect(self.logo_pic)
grid.addWidget(self.Logo_button, 1, 0)
grid.addWidget(self.LogoLabel, 1,1)
self.done_button = QtGui.QPushButton()
self.done_button.setText('Click this when all data is entered')
self.done_button.clicked.connect(self.finish_input_click)
grid.addWidget(self.done_button, 2,1)
def rt_button_click(self):
self.report_title = self.report_title_ask.text()
def logo_pic(self):
self.Logo_picture = unicode(QtGui.QFileDialog.getOpenFileName())
self.LogoLabel.setText(self.Logo_picture)
def finish_input_click(self):
self.report_title = self.report_title_ask.text()
self.close()
app = QtGui.QApplication(sys.argv)
cw = CompiledWindow()
cw.show()
Related
I'm a beginner to Pyside6 and mne-python. I want the raw.plot to block so I can interact with the figure. However, the program continue to run and print 'after window close' after the figure opened. According to mne documentation, https://mne.tools/stable/generated/mne.viz.plot_raw.html?highlight=plot_raw#mne.viz.plot_raw
I have set the parameter block to True, but it doesn't work.
import matplotlib
import mne, sys
from PySide6.QtWidgets import QMainWindow, QPushButton, QApplication
matplotlib.rcParams['font.sans-serif'] = ['Arial Unicode MS']
matplotlib.rcParams['axes.unicode_minus'] = False
matplotlib.use('qtAgg')
class Test(QMainWindow):
def __init__(self):
super(Test, self).__init__()
self.button = QPushButton('Plot raw')
self.button.clicked.connect(self.Show)
self.setCentralWidget(self.button)
def Show(self):
sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = (sample_data_folder / 'MEG' / 'sample' /
'sample_audvis_filt-0-40_raw.fif')
raw = mne.io.read_raw_fif(sample_data_raw_file)
raw.plot(block=True)
print('after window close')
app = QApplication(sys.argv)
main = Test()
main.show()
app.exec()
sys.exit()
When the program is running, it shows some information like this:
CoreApplication::exec: The event loop is already running.
I search for it, but don't find a solution to my problem. Is this an waring or error and can anyone give me a solution?
I have the following function (reduced) in the GUI class. My app is multithreaded so sometimes this function gets called multiple times before the previous once has finished. This shouldn't be a problem but it is.
So when this function is called simultaneously, multiple windows open as expected. For one of the windows I choose a location and click save, it works fine for that window, returning the file location picked. But when I do this the other windows close, returning a null string, despite me not having interacted with them.
Can anyone shed some light on why?
The function is being called via a pyqt signal if that's relevant.
def save_file_dialog(self, file_name):
save_file_name = QFileDialog.getSaveFileName(self, "Save As", file_name)[0]
EDIT:
Minimal reproducible example:
import threading
import sys
import time
from PyQt5.QtWidgets import QMainWindow, QApplication, QFileDialog
from PyQt5 import QtCore
class MainWindow(QMainWindow):
save_file = QtCore.pyqtSignal(str)
def __init__(self):
super(MainWindow, self).__init__()
self.save_file.connect(self.save_file_dialog)
def save_file_dialog(self, file_name):
save_file_name = QFileDialog.getSaveFileName(self, "Save As", file_name)[0]
print(save_file_name)
def different_thread():
x = 0
while x != 3:
window.save_file.emit("filename")
time.sleep(0.5)
x += 1
APP = QApplication(sys.argv)
window = MainWindow()
threading.Thread(target=different_thread).start()
sys.exit(APP.exec_())
Something interesting to note. Without the time.sleep it works as expected.
Unfortunately my setup means there will always be a delay, however long, between every signal emission.
EDIT 2:
I was able to partially resolve the issue.
Instead of:
save_file_name = QFileDialog.getSaveFileName(self, "Save As", file_name)[0]
I did this:
save_file_name = QFileDialog.getSaveFileName(self)[0]
For some reason unknown to me, getting rid of those arguments gives the expected behaviour.
The slot detectClipboardUrl of QClipboard::dataChanged() was called twice sometimes when I copy url in Google Chrome's address bar in this code, tested with PyQt5.7,Python3.5 on Win7 32bit, also on Linux Mint 18,
while I need the slot to be called only once , is this a bug ? any solutions ?
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MainWindow(QTableView):
def __init__(self, parent=None):
super().__init__(parent)
self.clipboard = QApplication.clipboard()
self.clipboard.dataChanged.connect(self.detectClipboardUrl)
#pyqtSlot()
def detectClipboardUrl(self):
print(self.clipboard.text())
if __name__ == "__main__":
app = QApplication(sys.argv)
ui = MainWindow()
ui.show()
sys.exit(app.exec_())
If the changes are duplicates, you can do something like:
class MainWindow(QTableView):
def __init__(self, parent=None):
self.clipboard = QApplication.clipboard()
self._cb_last = hash(self.clipboard.text())
self.clipboard.dataChanged.connect(self.detectClipboardUrl)
#pyqtSlot()
def detectClipboardUrl(self):
text = self.clipboard.text()
cb_current = hash(text)
if cb_current != self._cb_last:
print('clipboard text changed:', text)
self._cb_last = cb_current
The reason for using hash is simply to avoid keeping very large strings in memory.
Alternatively, if the two signals arrive very close together, you could use a QTimer to block any changes that occur within a few milliseconds of the first one.
UPDATE:
As I suspected, the problem is caused by a bug in Chromium: see Issue 173691.
I'm using PyQt to build a simple IDE and getting weird errors if you load an empty file. A small example script is posted below:
#!/usr/bin/env python
import sys
from PyQt4 import QtGui
class TestApp(QtGui.QMainWindow):
def __init__(self, filename=None):
super(TestApp, self).__init__()
self._editor = QtGui.QPlainTextEdit()
self._editor.modificationChanged.connect(self._change_modified)
self.setCentralWidget(self._editor)
self._editor.setPlainText('a')
def _change_modified(self, have_change):
print(have_change)
if __name__ == '__main__':
a = QtGui.QApplication([])
app = TestApp()
app.show()
sys.exit(a.exec_())
As expected, this shows a window with a plain text editor. As soon as the setPlainText method is called, the editor emits two events: One modificationChanged event with changes=True, a second with changes=False.
A bit weird, but fine.
However, if you change setPlainText('a') to setPlainText(''), only a single event is emitted, this time with changes=True. Even worse, after telling the editor it's not modified with setModified(False), it insists it's been changed somehow.
Does anyone know what's causing this and how I can work around this issue?
Update: It seems to be a bug & also affects QPlainTextEdit.clear().
The workaround below places a wrapper around the QPlainTextEdit to fix clear() and setPlainText('').
#!/usr/bin/env python
import sys
from PyQt4 import QtGui
class TestApp(QtGui.QMainWindow):
def __init__(self, filename=None):
super(TestApp, self).__init__()
self._editor = PlainTextEdit()
self._editor.modificationChanged.connect(self._change_modified)
self.setCentralWidget(self._editor)
self._editor.setPlainText('')
def _change_modified(self, have_change):
print(have_change)
class PlainTextEdit(QtGui.QPlainTextEdit):
def clear(self):
self.selectAll()
cursor = self.textCursor()
cursor.removeSelectedText()
doc = self.document()
doc.clearUndoRedoStacks()
doc.setModified(False)
self.modificationChanged.emit(False)
def setPlainText(self, text):
if text:
super(PlainTextEdit, self).setPlainText(text)
else:
self.clear()
if __name__ == '__main__':
a = QtGui.QApplication([])
app = TestApp()
app.show()
sys.exit(a.exec_())
It's a Qt bug, and the straightforward workaround is to check for empty contents if modifications are indicated.
EDIT2: model.hasChildren(parentIndex) returns True, but model.rowCount(parentIndex) returns 0. Is QFileSystemModel just fubar in PyQt?
EDIT: With a bit of adaptation this all works exactly as it should if I use QDirModel. This is deprecated, but maybe QFileSystemModel hasn't been fully implemented in PyQt?
I'm learning the Qt Model/View architecture at the moment, and I've found something that doesn't work as I'd expect it to. I've got the following code (adapted from Qt Model Classes):
from PyQt4 import QtCore, QtGui
model = QtGui.QFileSystemModel()
parentIndex = model.index(QtCore.QDir.currentPath())
print model.isDir(parentIndex) #prints True
print model.data(parentIndex).toString() #prints name of current directory
rows = model.rowCount(parentIndex)
print rows #prints 0 (even though the current directory has directory and file children)
The question:
Is this a problem with PyQt, have I just done something wrong, or am I completely misunderstanding QFileSystemModel? According to the documentation, model.rowCount(parentIndex) should return the number of children in the current directory. (I'm running this under Ubuntu with Python 2.6)
The QFileSystemModel docs say that it needs an instance of a Gui application, so I've also placed the above code in a QWidget as follows, but with the same result:
import sys
from PyQt4 import QtCore, QtGui
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
model = QtGui.QFileSystemModel()
parentIndex = model.index(QtCore.QDir.currentPath())
print model.isDir(parentIndex)
print model.data(parentIndex).toString()
rows = model.rowCount(parentIndex)
print rows
def main():
app = QtGui.QApplication(sys.argv)
widget = Widget()
widget.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I've solved it.
The reason to use QFileSystemModel as opposed to QDirModel is because QFileSystemModel loads the data from the filesystem in a separate thread. The problem with that is that if you try to print the number of children just after it's been constructed is that it won't have loaded the children yet. The way to fix the above code is to add the following:
self.timer = QtCore.QTimer(self)
self.timer.singleShot(1, self.printRowCount)
to the end of the constructor, and add a printRowCount method which will print the correct number of children. Phew.
Since you've already figured it out, just a couple of extra thoughts on what was going on with your model: QFileSystemModel::rowCount returns rows from the visibleChildren collection; I guess you're correctly identified the problem: at the time when you're checking row count it was not yet populated. I've changed your example without using timers; pls, check if it works for you:
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.model = QtGui.QFileSystemModel()
self.model.setRootPath(QtCore.QDir.currentPath())
def checkParent(self):
parentIndex = self.model.index(QtCore.QDir.currentPath())
print self.model.isDir(parentIndex)
print self.model.data(parentIndex).toString()
rows = self.model.rowCount(parentIndex)
print "row count:", rows
def main():
app = QtGui.QApplication(sys.argv)
widget = Widget()
widget.show()
app.processEvents(QtCore.QEventLoop.AllEvents)
widget.checkParent()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I believe your code should work correctly on any UI event after widget constructed is shown on the screen
regards