Conversation
Changes in 225 in order to prevent ValueError which appears in some cases.
|
Hi @Gdalik I thought I posted a response to this PR while I'm on mobile, but now that I pull up the web I realize it didn't post, so my apologies for the late response. I've heard reports of this error before, but I have never had a reproducible example. I don't see how this error occurs though, and I'm worried by implementing a fix like the one you suggested, we are merely masking a bug somewhere else in the library. Do you have an example you can share that triggers this error? |
|
Hi @j9ac9k ! Thanks for your reply. Nevertheless, I will try to give you a typical scenario. Here is the short screencast of my app: In the left bottom part, you can see the dockable window (“Audio panel”) with PlotWidget inside. The waveform is drawn with the PlotItem. The red cursor showing current playback position, and the grey labeled solid/dashed lines representing music bars/beats are corresponding subclass objects of InfiniteLine. The method chain causing the playback position change is triggered with sigMouseClicked Sorry for not being able to provide a meaningful excerpt from my code, and for being verbose. Please, let me know if you need any additional info from me. I hope this could help. |
|
Hi @Gdalik, I too have dabbled in audio processing https://github.com/j9ac9k/barney Although I never had great luck w/ the lower level QMedia objects, so I had to resort to soundfile and sounddevice libraries for reading in and playback. But to this PR, here's the relevant chunk of code. cev = [e for e in self.clickEvents if e.button() == ev.button()]
if cev:
if self.sendClickEvent(cev[0]):
ev.accept()
self.clickEvents.remove(cev[0])We construct the list the next thing that happens is we remove that element from the list of If you're able to reproduce the error in your own closed application, I would suggest inserting some print statements before/after the call to cev = [e for e in self.clickEvents if e.button() == ev.button()]
if cev:
print(f"Before self.sendClickEvent call event in self.clickEvents: {cev[0] in self.clickEvents}")
if self.sendClickEvent(cev[0]):
ev.accept()
print(f"After self.sendClickEvent call event in self.clickEvents: {cev[0] in self.clickEvents}")
self.clickEvents.remove(cev[0])If that event is no longer in I'm not saying there isn't a bug; there very well may be one, but I'm very nervous about trying to cover it up the way this PR attempts to do so. |
|
Hi @j9ac9k, Thanks for getting back and for sharing your audio processing project. I haven't launched it yet, but I have looked at it briefly, and I have already found some interesting and inspiring things for myself as an aspiring coding hobbyist with musical/audio engineering background. As for the current PR, I have followed your suggestion. And here is the sample of the console output I get when I manage to reproduce the error:
I will try to test the |
|
@j9ac9k , here is the And the output:
|
|
Thanks for the debug info; looks like the In the Can you modify your line print("--br5- if hasattr(item, 'mouseClickEvent'):")to print(f"--br5- {type(item)=}\t {(ev in self.click events)=}")Thanks for this info, this is really helpful! |
|
Hi @j9ac9k , Here it is:
|
|
Thanks @Gdalik It's getting narrowed down I think. Can you add print(f"--br6- {type(item)=}\t {(ev in self.click events)=}")just before if ev.isAccepted():Also, can you replace self.sigMouseClicked.emit(ev)with print(f"--br7- Before sigMouseClicked.emit {(ev in self.click events)=}")
self.sigMouseClicked.emit(ev)
print(f"--br8- After sigMouseClicked.emit {(ev in self.click events)=}")Thanks! |
|
My pleasure to help you, @j9ac9k !
[...]
|
|
Hmm... do you have It's hard to read from just the print output, but the duplicate output here is a little concerning... I don't understand why br7 is only being printed once but br8 is printed twice... oh, lastly, I would wrap the Thanks again for your debug efforts here! |
|
@j9ac9k , I will split my answer into some parts. First, the current code after all the modifications, just to make sure we are on the same page. |
|
that looks right to me 👍🏻 |
|
Second, the output. I don't know why GitHub formats the text like this ((. |
|
hmm....some interesting output: also why is br8 printing multiple times 🤔 ...this happens twice, with viewboxes This is because that try/except block needs to be indented over once more...so unrelated |
|
Now, as for my code. As I have mentioned before, I have Now, some excerpts from my code which could be important from my point of view: Please, let me know if you need more. |
Ah, sure, it's my fault here. Do you need more console output with the right try/except indent? |
|
I don't know if that matters, but I also have the |
|
Don't worry about the try/except indent, go ahead and fix it in case we want to do more runs later.
So, there are different coordinates, and you may need to use one of the map functions to get the correct coordinates; one thing you could try position = viewbox.mapSceneToView(ev.scenePos())Let me know if that gives you the "correct" coordinates. One of the most confusing aspects of working with the graphics view framework is knowing what coordinate system your coordinates are in...there are a ton of mapping functions and it can involve a fair amount of trial and error before you get it right. Try this out and see if you can avoid triggering this issue. The code you shared looks fine, but the bit about multiple signals emitting seems somewhat problematic. Perhaps a compromise in this PR would be to do something like... Replace if cev:
if self.sendClickEvent(cev[0]):
#print "sent click event"
ev.accept()
self.clickEvents.remove(cev[0])with if cev:
e = self.clickEvents.pop(0)
if self.sendClickEvent(e):
ev.accept()This change changes the order, but should ensure all the relevant operations occur. |
Cool! The ValueError seems to be gone, and the console output looks much more ordered! And thanks a lot for your hint. I have modified my I have removed the And I seem not to need the method which converted mouse positions to scene positions with formula Thank you so much! |
|
First thing first, was using Specifically, I want to make sure you're no longer getting a ValueError, without this change if cev:
e = self.clickEvents.pop(0)
if self.sendClickEvent(e):
ev.accept()To the point of the mouse positions, there are a ton of mapping methods: http://doc.qt.io/qt-6/qgraphicsitem.html#mapFromItem It's not easy to sort out which one is appropriate, but getting accurate coordinates for the mouse cursor for the view, scene, window, etc is doable, it just takes a little tinkering to get the right map methods. Given that events give access to the |
Nope, I have rolled back the changes in |
|
That reordering solution masks the issue ... this ValueError should not be occurring; there is a bug somewhere. With the simpler code, can you post some of that debug print statements again? Hoping that we don't have some duplicates here... |
|
Ok, what print statements should I leave?
Can it be at lower (e.g., Qt5) level? |
Yeah, but probably a bug in our library :) Leave the print statements in the |
|
Even better would be if you can provide a reproducible example that I can debug myself, perhaps that is possible now that your code is potentially simplified. |
I'm sorry, but I would have to write another test app to make it work :-). This is not a small/simple app, there are too many dependencies, cross-dependencies, etc., and I haven't strictly followed the MVC pattern, or something like this. |
|
I have changed the enumeration a little bit, so that it would better follow the branches.
|
|
Crud, this time the issue occurs when the In an earlier post you said you had Also wherever you connect `sigMouseClicked, can you add the following argument? sigMouseClicked.connect(..., type=pg.Qt.ConnectionType.UniqueConnection)This will raise an exception if you connect the same signal to the same slot more than once I believe. |
|
Now I have only
PyCharm doesn't see the reference to 'ConnectionType' as well, even before running the app. |
|
Here is the link to the whole module if that helps. |
|
That will teach me to go off of memory; I think it should be: type=pg.Qt.QtCore.Qt.ConnectionType.UniqueConnection |
|
Still no luck. I have the latest 0.13.1 version installed. |
|
I have PySide2, not PyQt5, does that matter? |
|
Oh, sorry. I have missed Qt after QtCore... Now it has launched |
Cool, with specifying the unique connection, do you still trigger the ValueError? if so, can you show the console output? |
|
|
(╯°□°)╯︵ ┻━┻ Having one line for br9.1 but two lines for br9.2 is a signal for sure here, I would imagine it would be due to that signal being connected to multiple places, which I suppose UniqueConnection wouldn't catch. Can you comment out |
|
Hi @j9ac9k , After commenting out The output pattern looks quite repetitive, like:
And I haven't noticed any double 9.2. |
|
After dabbling for a while, I have found out that these issues are correlated with the number of BeatLines. When there are no/few of them, it's hard to reproduce these errors and those duplications of 9.2. But when there are hundreds/thousands of them, everything noticeably slows down, and the issues occur. The more lines, the more issues. Though, the |
|
@j9ac9k , I seem to have found the real source of the issue. |
|
Nice troubleshooting! Generally speaking,
Now that we've gotten to the bottom of this, I think we can try/except and emit a warning. Something along the lines of if cev:
if self.sendClickEvent(cev[0]):
ev.accept()
try:
self.clickEvents.remove(cev[0])
except ValueError:
warnings.warn(
("A ValueError can occur here with errant QApplication.processEvent() calls, see "
"https://github.com/pyqtgraph/pyqtgraph/pull/2580 for more discussion."),
RuntimeWarning,
stacklevel=2
) |
|
Thank you very much for your time, efforts and expertise! |

Changes in 225 in order to prevent ValueError which appears in some cases.