EnMAP-Box main window drag move access violation of
Issue #1344
closed
- Open EnMAP-Box
- Open & close a Map View
- Move EnMAP-Box to second screen (move fast between 1st and 2nd screen in both directions)
Exception is raised in qgsmapcanvas.cpp (sipPySelf QgsMapCanvas instance) in line:
mScreenDpiChangedConnection = connect( window()->windowHandle()->screen(), &QScreen::physicalDotsPerInchChanged, this, &QgsMapCanvas::updateDevicePixelFromScreen );
updateDevicePixelFromScreen();
Line Context in qgsmapcanvas.cpp:
void QgsMapCanvas::showEvent( QShowEvent *event )
{
Q_UNUSED( event )
updateDevicePixelFromScreen();
// keep device pixel ratio up to date on screen or resolution change
if ( window()->windowHandle() )
{
connect( window()->windowHandle(), &QWindow::screenChanged, this, [ = ]( QScreen * )
{
disconnect( mScreenDpiChangedConnection );
mScreenDpiChangedConnection = connect( window()->windowHandle()->screen(), &QScreen::physicalDotsPerInchChanged, this, &QgsMapCanvas::updateDevicePixelFromScreen );
updateDevicePixelFromScreen();
} );
mScreenDpiChangedConnection = connect( window()->windowHandle()->screen(), &QScreen::physicalDotsPerInchChanged, this, &QgsMapCanvas::updateDevicePixelFromScreen );
}
}
Call Stack:
Update: Python example to reproduce the error. Can be run from QGIS python shell or from PyCharm:
import gc
import sys
from qgis.PyQt.QtGui import QScreen
from qgis.PyQt.QtWidgets import QWidget, QVBoxLayout, QPushButton
from qgis.core import QgsApplication
from qgis.gui import QgsMapCanvas
from qgis.testing import start_app
app = QgsApplication.instance()
if not isinstance(app, QgsApplication):
app = start_app()
call_exec = True
else:
call_exec = False
assert len(app.screens()) > 1, 'This test requires at least 2 screens'
canvas = QgsMapCanvas()
class MyWidget(QWidget):
def __init__(self, *args, **kwds):
super(MyWidget, self).__init__(*args, **kwds)
self.btn = QPushButton('Remove canvas')
self.btn.clicked.connect(self.onClicked)
self.canvas = canvas
layout = QVBoxLayout()
layout.addWidget(self.btn)
layout.addWidget(self.canvas)
self.setLayout(layout)
def onClicked(self):
if isinstance(self.canvas, QgsMapCanvas):
# self.layout().takeAt(self.layout().indexOf(self.canvas))
self.layout().removeWidget(self.canvas)
self.canvas.setParent(None)
self.canvas = None
app.processEvents()
gc.collect()
print(f'REFCOUNT={sys.getrefcount(canvas)}')
# 1. create widget with QgsMapCanvas on default screen
w = MyWidget()
w.show()
app.processEvents()
# 2. Remove QgsMapCanvas, but keep a python reference on, so that is still exists
w.btn.click()
app.processEvents()
# 3. Move widget to 2nd screen. This raises an access violation on windows systems
nextScreen: QScreen = [s for s in app.screens() if s != w.screen()][0]
nextScreenCenter = nextScreen.geometry().center()
w.move(nextScreenCenter)
app.processEvents()
if call_exec is True:
app.exec()
Comments (5)
-
reporter -
reporter QGIS API issue:
https://github.com/qgis/QGIS/issues/48438
Potential workaround: remove all reference to a MapCanvas before closing the MapDock
-
reporter - changed status to resolved
Closed by https://github.com/qgis/QGIS/pull/48551 (Requires QGIS update)
-
reporter - edited description
-
reporter - changed status to closed
confirmed fix in QGIS master (3.25)
- Log in to comment
Script to reproduce the exception (move the created DockArea between screens):