Phoenix icon indicating copy to clipboard operation
Phoenix copied to clipboard

Mouse scroll events are not correctly passed to matplotlib in 4.1.0

Open StephanSchwebel opened this issue 4 years ago • 19 comments

Win10 64bit: wxPython 4.1.0 pypi: 3.7.6 Anaconda: matplotlib 3.2.2

I am trying to use mouse scroll events in a matplotlib canvas but the mouse scroll event data is wrong. The attached script will print the mouse scroll events. I have observerd:

  • that the "button" property is always "down" when it should switch between "up" and "down" depending on the user input.
  • xy coordinates are not correct.
  • xydata is None

Additional information: This seems to be related to https://github.com/matplotlib/matplotlib/issues/17513 The script and events work correctly when using wxPython 4.0.7 In 4.1.0 the events are sometimes correct when holding the right mouse-button down.

Example output from 4.1.0 scroll_event: xy=(32766, 484) xydata=(None, None) button=down dblclick=False inaxes=None scroll_event: xy=(32766, 484) xydata=(None, None) button=down dblclick=False inaxes=None scroll_event: xy=(32766, 484) xydata=(None, None) button=down dblclick=False inaxes=None

Example output from 4.0.7 scroll_event: xy=(321, 241) xydata=(2.3669753832761042, 2.161450996881461) button=down dblclick=False inaxes=AxesSubplot(0.125,0.125;0.775x0.755) scroll_event: xy=(321, 241) xydata=(2.3669753832761042, 2.161450996881461) button=up dblclick=False inaxes=AxesSubplot(0.125,0.125;0.775x0.755) scroll_event: xy=(321, 241) xydata=(2.3669753832761042, 2.161450996881461) button=up dblclick=False inaxes=AxesSubplot(0.125,0.125;0.775x0.755) scroll_event: xy=(321, 241) xydata=(2.3669753832761042, 2.161450996881461) button=up dblclick=False inaxes=AxesSubplot(0.125,0.125;0.775x0.755)

import matplotlib
matplotlib.use('WXAgg')

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure

import wx

class CanvasPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)
        self.Fit()
        self.canvas.mpl_connect("scroll_event", self.OnMouseScroll)

    def draw(self):
        x = [1,2,3,4]
        y = [1,2,3,4]
        self.axes.plot(x, y)

    def OnMouseScroll(self, e):
        print(e)

if __name__ == "__main__":
    app = wx.PySimpleApp()
    fr = wx.Frame(None, title='test')
    panel = CanvasPanel(fr)
    panel.draw()
    fr.Show()
    app.MainLoop()

StephanSchwebel avatar Jul 02 '20 08:07 StephanSchwebel

Seems to possibly be platform specific also. I can't reproduce with wxPy 4.1.0 and matplotlib 3.2.2 on Linux (Ubuntu 18.04).

swt2c avatar Jul 02 '20 15:07 swt2c

I am having the same exact issue: Scroll wheel is always reported as "down" no matter the wheel direction.

WxPython version: 4.1.1 Matplotlib version: 3.3.4

Using wxPython version 4.0.7, everything is fine again. However, version 4.1.1 is needed

elesbb avatar Feb 11 '21 15:02 elesbb

I have the same issue with the wheel direction always reported as down, and the number of lines as 382. Seems to be an issue with the interaction at the matplotlib canvas Windows 10 Python 3.8 WxPython 4.0.7post2 or 4.1.1 Matplotlib 3.4.3 I tried binding the wx.EVT_MOUSEWHEEL at the Panel and recursively Connect it for all children. The event.WheelRotation works correctly while the mouse is over the toolbar and rest of the panel, but fails when moving the scroll wheel over the matplotlib FigureCanvasWxAgg

snowdonr avatar Oct 19 '21 21:10 snowdonr

I found the same issue in:

Win 10, Python 3.9.10 (miniconda), matplotlib 3.5.1, wxPython 4.1.1

One add-on, the event.step value is also incorrect. Typically always negative regardless of direction, and around a value of -12000 or so, as opposed to 1 or 2 or 3.

I used StephanSchwebel's script, with an additional print out of e.step for my purpose.

Did not find a workaround yet, except to go back to wxPython 4.0.4 and Python 3.7 (on my other environment).

bsoher avatar Mar 02 '22 22:03 bsoher

I have just tried the script in a debugger on Windows. Incidentally, I picked two of my installations that are almost the same, just 32 vs. 64 bit. It seems to be a 64 bit problem. matplotlib backend_wx._FigureCanvasWxBase._onMouseWheel uses GetWheelDelta etc. to decide for 'up' or 'down'. The values are completely off.

Correct behaviour:

3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)]
(4, 1, 0, '')

backend_wx._FigureCanvasWxBase._onMouseWheel:
    evt.GetWheelDelta() 120
    evt.GetWheelRotation() 120
    evt.GetLinesPerAction() 3

Wrong behaviour:

3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40) [MSC v.1900 64 bit (AMD64)]
(4, 1, 0, '')

backend_wx._FigureCanvasWxBase._onMouseWheel:
    evt.GetWheelDelta() 10045
    evt.GetWheelRotation() 417
    evt.GetLinesPerAction() -31992

Honestly, I'm a bit surprised that none of the reporters has a debugger available. This could have speeded up things a lot...

DietmarSchwertberger avatar Mar 02 '22 22:03 DietmarSchwertberger

I'm surprised that a pure wxPython script does not have issues with the EVT_MOUSEWHEEL.

wxPythonIssue1707_Panel.py.txt

DietmarSchwertberger avatar Mar 02 '22 22:03 DietmarSchwertberger

OK, I have further tracked down the issue. matplotlib is storing references to wx events. If I modify backend_wx._FigureCanvasWxBase._onMotion: FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=evt) to FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=None) then the problem goes away. A workaround would be to derive your own class and override the _onMotion method accordingly

@swt2c : Please see attached script with handlers for EVT_MOTION and EVT_MOUSEWHEEL. It's showing the same problem for me due to the line self.event = event in onMotion. Is it 'legal' for a wxPython application to store a reference to an event instance? I would think that the reference should be removed at the end of the matplotlib event handler.

wxPythonIssue1707_Panel.py.txt

DietmarSchwertberger avatar Mar 02 '22 23:03 DietmarSchwertberger

I don't know of any technical reason why you shouldn't be able to retain a reference to a mouse event. The behavior you are seeing is really strange. GetWheelDelta() is populated using a constant so it should always be 120. Because you're seeing something other than 120 suggests to me that there might be some sort of memory corruption going on here.

swt2c avatar Mar 03 '22 00:03 swt2c

Hi @DietmarSchwertberger and thanks for the really useful information. Apologies for any loose/incorrect terminology below, I'm still learning how to post.

I've reworked the @StephanSchwebel test code to contain a local version of the FigureCanvasWxAgg backend to test if that can give a proper 'step' value in my matplotlib event (my original problem). I found that I had to override both _OnMotion() and _onMouseWheel() methods to get proper behaviour. Both contained ongoing references to the event in their code.

Thought it might be useful to the thread.

import matplotlib
matplotlib.use('WXAgg')

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.backend_bases import FigureCanvasBase
from matplotlib.figure import Figure

import wx

class LocalFigureCanvasWxAgg(FigureCanvasWxAgg):

    def _onMouseWheel(self, event):
         """Translate mouse wheel events into matplotlib events"""
         # Determine mouse location
         x = event.GetX()
         y = self.figure.bbox.height - event.GetY()
         # Convert delta/rotation/rate into a floating point step size
         step = event.LinesPerAction * event.WheelRotation / event.WheelDelta
         # Done handling event
         event.Skip()
         # Mac gives two events for every wheel event; skip every second one.
         if wx.Platform == '__WXMAC__':
             if not hasattr(self, '_skipwheelevent'):
                 self._skipwheelevent = True
             elif self._skipwheelevent:
                 self._skipwheelevent = False
                 return  # Return without processing event
             else:
                 self._skipwheelevent = True
         FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=None) #event)

    def _onMotion(self, event):
        """Start measuring on an axis."""
        x = event.GetX()
        y = self.figure.bbox.height - event.GetY()
        event.Skip()
        FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=None) #event)

class CanvasPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = LocalFigureCanvasWxAgg(self, -1, self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)
        self.Fit()
        self.canvas.mpl_connect("scroll_event", self.OnMouseScroll)

    def draw(self):
        x = [1,2,3,4]
        y = [1,2,3,4]
        self.axes.plot(x, y)

    def OnMouseScroll(self, e):
        print(str(e) + ' step = ' + str(e.step))

if __name__ == "__main__":
    app = wx.PySimpleApp()
    fr = wx.Frame(None, title='test')
    panel = CanvasPanel(fr)
    panel.draw()
    fr.Show()
  app.MainLoop()

bsoher avatar Mar 03 '22 01:03 bsoher

I think this is related to https://github.com/wxWidgets/Phoenix/issues/2034

chiga17 avatar Mar 03 '22 10:03 chiga17

I can indeed reproduce this issue on Windows with wxPython 4.1.1. However, the problem seems to be fixed in the latest snapshots. Can anyone else confirm please?

swt2c avatar Mar 04 '22 00:03 swt2c

Hi @swt2c I installed (pip) wheel wxPython-4.1.2a1.dev5259+d3bdb143 from https://wxpython.org/Phoenix/snapshot-builds/ into my python 3.9 env in miniconda. I ran my test code (see above) and it behaved properly: x,y xdata,ydata button dblclick and step values all seemed to track with mouse position and wheel roll direction properly. Thanks for pointing that out.

bsoher avatar Mar 04 '22 15:03 bsoher

This issue has been mentioned on Discuss wxPython. There might be relevant details there:

https://discuss.wxpython.org/t/a-problem-with-event-objects/35766/3

RobinD42 avatar Mar 04 '22 15:03 RobinD42

What's strange is that I have no idea what might have fixed this. My best guess was that it had something to do with sip 4 and moving to sip 5 fixed it.

swt2c avatar Mar 04 '22 15:03 swt2c

I have also built wxPython now and also don't see the issue.

DietmarSchwertberger avatar Mar 04 '22 21:03 DietmarSchwertberger

Confirmed that the problem is fixed in wx 4.1.2a1 with matplotlib 3.5.1/WXAgg. @swt2c, I don't think the sip version is the only reason the problem has been fixed because there was no problem with wx 4.0.7. Actually, I don't think the problem has been completely resolved, but I think it's just hidden and a similar problem will appear someday...

komoto48g avatar Mar 05 '22 12:03 komoto48g

As your example code from the first post on Discuss still fails, this might be a good starting point for debugging. https://discuss.wxpython.org/t/a-problem-with-event-objects/35766/2

DietmarSchwertberger avatar Mar 05 '22 15:03 DietmarSchwertberger

Read Exception and backtrace look like this:

grafik

>	_core_d.cp310-win_amd64.pyd!meth_wxObject_GetClassInfo(_object * sipSelf, _object * sipArgs) Zeile 47	C++
 	python310_d.dll!cfunction_call(_object * func, _object * args, _object * kwargs) Zeile 552	C
 	python310_d.dll!_PyObject_MakeTpCall(_ts * tstate, _object * callable, _object * const * args, __int64 nargs, _object * keywords) Zeile 215	C
 	python310_d.dll!_PyObject_VectorcallTstate(_ts * tstate, _object * callable, _object * const * args, unsigned __int64 nargsf, _object * kwnames) Zeile 112	C
 	python310_d.dll!PyObject_CallOneArg(_object * func, _object * arg) Zeile 185	C
 	python310_d.dll!property_descr_get(_object * self, _object * obj, _object * type) Zeile 1607	C
 	python310_d.dll!_PyObject_GenericGetAttrWithDict(_object * obj, _object * name, _object * dict, int suppress) Zeile 1243	C
 	python310_d.dll!PyObject_GenericGetAttr(_object * obj, _object * name) Zeile 1323	C
 	python310_d.dll!PyObject_GetAttr(_object * v, _object * name) Zeile 922	C
 	python310_d.dll!builtin_getattr(_object * self, _object * const * args, __int64 nargs) Zeile 1106	C
 	python310_d.dll!cfunction_vectorcall_FASTCALL(_object * func, _object * const * args, unsigned __int64 nargsf, _object * kwnames) Zeile 430	C
 	python310_d.dll!_PyObject_VectorcallTstate(_ts * tstate, _object * callable, _object * const * args, unsigned __int64 nargsf, _object * kwnames) Zeile 115	C
 	[Inlineframe] python310_d.dll!PyObject_Vectorcall(_object *) Zeile 123	C
 	python310_d.dll!call_function(_ts * tstate, PyTraceInfo * trace_info, _object * * * pp_stack, __int64 oparg, _object * kwnames) Zeile 5870	C
 	python310_d.dll!_PyEval_EvalFrameDefault(_ts * tstate, _frame * f, int throwflag) Zeile 4214	C
 	[Inlineframe] python310_d.dll!_PyEval_EvalFrame(_ts *) Zeile 46	C
 	python310_d.dll!_PyEval_Vector(_ts * tstate, PyFrameConstructor * con, _object * locals, _object * const * args, unsigned __int64 argcount, _object * kwnames) Zeile 5072	C
 	python310_d.dll!_PyFunction_Vectorcall(_object * func, _object * const * stack, unsigned __int64 nargsf, _object * kwnames) Zeile 342	C
 	python310_d.dll!_PyObject_VectorcallTstate(_ts * tstate, _object * callable, _object * const * args, unsigned __int64 nargsf, _object * kwnames) Zeile 115	C
 	[Inlineframe] python310_d.dll!PyObject_Vectorcall(_object *) Zeile 123	C
 	python310_d.dll!call_function(_ts * tstate, PyTraceInfo * trace_info, _object * * * pp_stack, __int64 oparg, _object * kwnames) Zeile 5870	C
 	python310_d.dll!_PyEval_EvalFrameDefault(_ts * tstate, _frame * f, int throwflag) Zeile 4214	C
 	[Inlineframe] python310_d.dll!_PyEval_EvalFrame(_ts *) Zeile 46	C
 	python310_d.dll!_PyEval_Vector(_ts * tstate, PyFrameConstructor * con, _object * locals, _object * const * args, unsigned __int64 argcount, _object * kwnames) Zeile 5072	C
 	python310_d.dll!_PyFunction_Vectorcall(_object * func, _object * const * stack, unsigned __int64 nargsf, _object * kwnames) Zeile 342	C
 	python310_d.dll!_PyObject_VectorcallTstate(_ts * tstate, _object * callable, _object * const * args, unsigned __int64 nargsf, _object * kwnames) Zeile 114	C
 	python310_d.dll!method_vectorcall(_object * method, _object * const * args, unsigned __int64 nargsf, _object * kwnames) Zeile 83	C
 	python310_d.dll!PyVectorcall_Call(_object * callable, _object * tuple, _object * kwargs) Zeile 255	C
 	python310_d.dll!_PyObject_Call(_ts * tstate, _object * callable, _object * args, _object * kwargs) Zeile 290	C
 	python310_d.dll!PyObject_CallObject(_object * callable, _object * args) Zeile 400	C
 	_core_d.cp310-win_amd64.pyd!wxPyCallback::EventThunker(wxEvent & event) Zeile 72	C++
 	wxbase315ud_vc140_x64.dll!wxAppConsoleBase::HandleEvent(wxEvtHandler * handler, void(wxEvtHandler::*)(wxEvent &) func, wxEvent & event) Zeile 655	C++
 	wxbase315ud_vc140_x64.dll!wxAppConsoleBase::CallEventHandler(wxEvtHandler * handler, wxEventFunctor & functor, wxEvent & event) Zeile 667	C++
 	wxbase315ud_vc140_x64.dll!wxEvtHandler::ProcessEventIfMatchesId(const wxEventTableEntryBase & entry, wxEvtHandler * handler, wxEvent & event) Zeile 1420	C++
 	wxbase315ud_vc140_x64.dll!wxEvtHandler::SearchDynamicEventTable(wxEvent & event) Zeile 1890	C++
 	wxbase315ud_vc140_x64.dll!wxEvtHandler::TryHereOnly(wxEvent & event) Zeile 1611	C++
 	wxbase315ud_vc140_x64.dll!wxEvtHandler::TryBeforeAndHere(wxEvent & event) Zeile 3975	C++
 	wxbase315ud_vc140_x64.dll!wxEvtHandler::ProcessEventLocally(wxEvent & event) Zeile 1548	C++
 	wxbase315ud_vc140_x64.dll!wxEvtHandler::ProcessEvent(wxEvent & event) Zeile 1521	C++
 	_core_d.cp310-win_amd64.pyd!sipwxFrame::ProcessEvent(wxEvent & event) Zeile 297	C++
 	wxbase315ud_vc140_x64.dll!wxEvtHandler::SafelyProcessEvent(wxEvent & event) Zeile 1639	C++
 	wxmsw315ud_core_vc140_x64.dll!wxWindowBase::HandleWindowEvent(wxEvent & event) Zeile 1556	C++
 	wxmsw315ud_core_vc140_x64.dll!wxWindow::HandleMouseWheel(wxMouseWheelAxis axis, unsigned __int64 wParam, __int64 lParam) Zeile 6089	C++
 	wxmsw315ud_core_vc140_x64.dll!wxWindow::MSWHandleMessage(__int64 * result, unsigned int message, unsigned __int64 wParam, __int64 lParam) Zeile 3139	C++
 	wxmsw315ud_core_vc140_x64.dll!wxWindow::MSWWindowProc(unsigned int message, unsigned __int64 wParam, __int64 lParam) Zeile 3883	C++
 	wxmsw315ud_core_vc140_x64.dll!wxNonOwnedWindow::MSWWindowProc(unsigned int message, unsigned __int64 wParam, __int64 lParam) Zeile 259	C++
 	wxmsw315ud_core_vc140_x64.dll!wxTopLevelWindowMSW::MSWWindowProc(unsigned int message, unsigned __int64 wParam, __int64 lParam) Zeile 324	C++
 	wxmsw315ud_core_vc140_x64.dll!wxFrame::MSWWindowProc(unsigned int message, unsigned __int64 wParam, __int64 lParam) Zeile 912	C++
 	wxmsw315ud_core_vc140_x64.dll!wxWndProc(HWND__ * hWnd, unsigned int message, unsigned __int64 wParam, __int64 lParam) Zeile 2924	C++
 	[Externer Code]	
 	wxmsw315ud_core_vc140_x64.dll!wxGUIEventLoop::ProcessMessage(tagMSG * msg) Zeile 166	C++
 	wxmsw315ud_core_vc140_x64.dll!wxGUIEventLoop::Dispatch() Zeile 226	C++
 	wxbase315ud_vc140_x64.dll!wxEventLoopManual::ProcessEvents() Zeile 234	C++
 	wxbase315ud_vc140_x64.dll!wxEventLoopManual::DoRun() Zeile 288	C++
 	wxbase315ud_vc140_x64.dll!wxEventLoopBase::Run() Zeile 87	C++
 	wxbase315ud_vc140_x64.dll!wxAppConsoleBase::MainLoop() Zeile 377	C++
 	_core_d.cp310-win_amd64.pyd!wxPyApp::MainLoop() Zeile 314	C++
 	_core_d.cp310-win_amd64.pyd!meth_wxPyApp_MainLoop(_object * sipSelf, _object * sipArgs) Zeile 1968	C++
 	python310_d.dll!cfunction_call(_object * func, _object * args, _object * kwargs) Zeile 552	C
 	python310_d.dll!_PyObject_MakeTpCall(_ts * tstate, _object * callable, _object * const * args, __int64 nargs, _object * keywords) Zeile 215	C
 	python310_d.dll!_PyObject_VectorcallTstate(_ts * tstate, _object * callable, _object * const * args, unsigned __int64 nargsf, _object * kwnames) Zeile 112	C
 	[Inlineframe] python310_d.dll!PyObject_Vectorcall(_object *) Zeile 123	C
 	python310_d.dll!call_function(_ts * tstate, PyTraceInfo * trace_info, _object * * * pp_stack, __int64 oparg, _object * kwnames) Zeile 5870	C
 	python310_d.dll!_PyEval_EvalFrameDefault(_ts * tstate, _frame * f, int throwflag) Zeile 4183	C
 	[Inlineframe] python310_d.dll!_PyEval_EvalFrame(_ts *) Zeile 46	C
 	python310_d.dll!_PyEval_Vector(_ts * tstate, PyFrameConstructor * con, _object * locals, _object * const * args, unsigned __int64 argcount, _object * kwnames) Zeile 5072	C
 	python310_d.dll!_PyFunction_Vectorcall(_object * func, _object * const * stack, unsigned __int64 nargsf, _object * kwnames) Zeile 342	C
 	python310_d.dll!_PyObject_VectorcallTstate(_ts * tstate, _object * callable, _object * const * args, unsigned __int64 nargsf, _object * kwnames) Zeile 115	C
 	[Inlineframe] python310_d.dll!PyObject_Vectorcall(_object *) Zeile 123	C
 	python310_d.dll!call_function(_ts * tstate, PyTraceInfo * trace_info, _object * * * pp_stack, __int64 oparg, _object * kwnames) Zeile 5870	C
 	python310_d.dll!_PyEval_EvalFrameDefault(_ts * tstate, _frame * f, int throwflag) Zeile 4199	C
 	[Inlineframe] python310_d.dll!_PyEval_EvalFrame(_ts *) Zeile 46	C
 	python310_d.dll!_PyEval_Vector(_ts * tstate, PyFrameConstructor * con, _object * locals, _object * const * args, unsigned __int64 argcount, _object * kwnames) Zeile 5072	C
 	python310_d.dll!PyEval_EvalCode(_object * co, _object * globals, _object * locals) Zeile 1135	C
 	python310_d.dll!run_eval_code_obj(_ts * tstate, PyCodeObject * co, _object * globals, _object * locals) Zeile 1291	C
 	python310_d.dll!run_mod(_mod * mod, _object * filename, _object * globals, _object * locals, PyCompilerFlags * flags, _arena * arena) Zeile 1312	C
 	python310_d.dll!pyrun_file(_iobuf * fp, _object * filename, int start, _object * globals, _object * locals, int closeit, PyCompilerFlags * flags) Zeile 1208	C
 	python310_d.dll!_PyRun_SimpleFileObject(_iobuf * fp, _object * filename, int closeit, PyCompilerFlags * flags) Zeile 456	C
 	python310_d.dll!_PyRun_AnyFileObject(_iobuf * fp, _object * filename, int closeit, PyCompilerFlags * flags) Zeile 90	C
 	python310_d.dll!pymain_run_file_obj(_object * program_name, _object * filename, int skip_source_first_line) Zeile 353	C
 	python310_d.dll!pymain_run_file(const PyConfig * config) Zeile 372	C
 	python310_d.dll!pymain_run_python(int * exitcode) Zeile 587	C
 	python310_d.dll!Py_RunMain() Zeile 668	C
 	python310_d.dll!pymain_main(_PyArgv * args) Zeile 697	C
 	python310_d.dll!Py_Main(int argc, wchar_t * * argv) Zeile 709	C
 	python_d.exe!wmain(int argc, wchar_t * * argv) Zeile 10	C

DietmarSchwertberger avatar Mar 05 '22 17:03 DietmarSchwertberger

This might be related to a wxWidgets/wxPython <-> sip interation. Anyway, not keeping a reference should fix the issue. See https://github.com/matplotlib/matplotlib/issues/22211#issuecomment-1065424567

DietmarSchwertberger avatar Mar 11 '22 22:03 DietmarSchwertberger