PyQtGraph: prevent QScrollArea scrolling when panning plot - pyqt

In PyQtGraph you can zoom into the plots with the scroll wheel. However, when embedding PyQtGraph inside a QScrollArea, scrolling both zooms into the hovered plot AND scrolls the QScrollArea.
Minimal reproducable code:
from PyQt5.QtWidgets import QApplication, QScrollArea, QMainWindow
import pyqtgraph as pg
app = QApplication([])
window = QMainWindow()
scroll = QScrollArea(window)
window.setCentralWidget(scroll)
frame = pg.GraphicsLayoutWidget()
plot = frame.addPlot().plot([1,2,3], [2,5,10])
scroll.setWidget(frame)
scroll.setWidgetResizable(True)
frame.setFixedHeight(600)
window.setFixedHeight(500)
window.show()
app.exec_()
I tried googling the issue, and I found a way to stop panning and allow scrolling, however I want it the other way around: prevent scrolling and allow panning.
Is it possible inside PyQtGraph to stop QScrollArea scrolling when a plot is hovered?

The solution is to cancel the wheelEvent of QScrollArea:
from PyQt5.QtWidgets import QApplication, QScrollArea, QMainWindow
import pyqtgraph as pg
class ScrollArea(QScrollArea):
def wheelEvent(self, event):
pass
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
window = QMainWindow()
scroll = ScrollArea(window)
window.setCentralWidget(scroll)
frame = pg.GraphicsLayoutWidget()
plot = frame.addPlot().plot([1, 2, 3], [2, 5, 10])
scroll.setWidget(frame)
scroll.setWidgetResizable(True)
frame.setFixedHeight(600)
window.setFixedHeight(500)
window.show()
sys.exit(app.exec_())

Related

Problems with matplotlib blitted cursor embeded in PyQt6 gui

I´m currently developing a software to process spectroscopic data using python. I´m using PyQt6 to design the gui and matplotlib to plot the data. To simplify the data selection I added a cursor widget from matplotlib to the axes. For improved performace I used the blitting mode.
Here´s a minimal code example:
# Import packages
from PyQt6.QtWidgets import QMainWindow, QApplication, QWidget, QVBoxLayout
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.widgets import Cursor
from matplotlib.figure import Figure
import numpy as np
# Main window
class MainWindow(QMainWindow):
def __init__(self):
# Initialize QMainWindow
super().__init__()
# Get MplWidget
self.mpl_widget = MplWidget()
# Set MplWidget as central widget
self.setCentralWidget(self.mpl_widget)
# Create axes
self.ax = self.mpl_widget.canvas.figure.add_subplot(111)
# Reference Cursor
self.cursor = Cursor(self.ax, useblit=True)
# Plot some random stuff
x, y = np.random.rand(100), np.random.rand(100)
self.ax.scatter(x, y)
# Show app
self.show()
# MplCanvas
class MplWidget(QWidget):
def __init__(self, parent=None):
# Initialize QWidget
super().__init__(parent)
# Create canvas
self.canvas = FigureCanvas(Figure())
# Set constrained layout
self.canvas.figure.set_constrained_layout(True)
# Create layout
layout = QVBoxLayout()
# Add canvas
layout.addWidget(self.canvas)
# Set layout
self.setLayout(layout)
# Initialize app
app = QApplication([])
UI = MainWindow()
app.exec()
Generally everything works fine, the cursor appears when hovering the axis and dissapears when leaving it, but when the mouse enters the axis, the whole axis content moves a little bit. Sometimes the figure edges also change their colors, e.g. from black to gray.
Here are two gifs to explain the phenomenon:
Does anyone know how to solve this problem?

Each character in text is cut off

When trying to plot labels in my application, the right side of each character in the text is cut off by a few pixels. Disabling opengl seems to fix the issue but I need opengl enabled for the application. Setting windows scaling to 125% seems to minimize/make this clipping issue go away, but there must be a better solution to this.Each character in the text is cut off on the right
Using pyside6 6.3.1, pyopengl 3.1.6, pyqtgraph 0.12.4
import os
import sys
from PySide6.QtWidgets import QApplication, QMainWindow
import pyqtgraph as pg
from pyqtgraph import GraphicsLayoutWidget
from PySide6.QtCore import Qt, QPointF
class PlotCanvas(GraphicsLayoutWidget):
def __init__(self):
pg.setConfigOption("antialias", True)
pg.setConfigOption("useOpenGL", True)
pg.setConfigOption("enableExperimental", False)
pg.setConfigOption("background", "w")
pg.setConfigOption("foreground", "k")
super().__init__()
self.mainplot = self.addPlot()
self.setup_fig()
def setup_fig(self):
""" Setup an initial plot.
"""
self.mainplot.setRange(
xRange=(-10, 1000), yRange=(-10, 2500), disableAutoRange=True
)
self.mainplot.setLabel("left", "Money", units="$")
self.mainplot.setLabel("bottom", "Time", units="s")
self.mousept = pg.TextItem(anchor=(0, 0), border=None)
self.mainplot.addItem(self.mousept)
pg.SignalProxy(
self.mainplot.scene().sigMouseMoved,
rateLimit=30,
slot=self.mouse_moved_update,
)
self.mainplot.scene().sigMouseMoved.connect(self.mouse_moved_update)
def mouse_moved_update(self, evt):
"""Show coordinate by the mousepointer and update on movements.
"""
mouse_point = self.mainplot.vb.mapSceneToView(evt)
plot_point = self.mainplot.vb.mapSceneToView(QPointF(evt.x() + 15, evt.y()))
self.mousept.setHtml(
"<span style='font-size: 10pt; color: %s; border-style: solid'>"
"x:%0.1f, y:%0.1f</span>" % ('black', mouse_point.x(), mouse_point.y())
)
self.mousept.setPos(plot_point.x(), plot_point.y())
def main():
os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1"
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication([])
window = QMainWindow()
window.setCentralWidget(PlotCanvas())
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

PyQt5 fullscreen unwanted behavior on ubuntu

I'm running a pyqt5 application on an ubuntu and when the app is in full screen mode, I get this behavior of the dock and title bar popping over the application when a dialog box is clicked. When the dialog box is closed, everything goes back to normal. This issue doesn't happen on my intel but happens on ARM64. My system is the Jetson AGX Xavier 32GB. I've posted a sample code below that reproduces the issue.
I saw another post that suggested in setting the window flag Qt.X11BypassWindowManagerHint or Qt.BypassWindowManagerHint, even though it came with some issues but that didn't work either.
Any help would be greatly appriciated.
from PyQt5.QtWidgets import QComboBox, QVBoxLayout, QWidget, QHBoxLayout, QApplication, QFileDialog, QPushButton, QMainWindow
from PyQt5.QtCore import Qt
import sys
import pyautogui
class TestCode(QMainWindow):
def __init__(self):
super(TestCode, self).__init__()
self.OpenDialog = QPushButton()
self.OpenDialog.setText("OPEN D BOX")
self.OpenDialog.clicked.connect(self.openDBox)
self.closeWindow = QPushButton()
self.closeWindow.setText("CLOSE")
self.closeWindow.clicked.connect(self.close)
colors = ["Yellow", "Magenta", "Black", "White",
"Green", "Blue", "Cyan", "Red"]
self.drop_down = QComboBox()
for color in colors:
self.drop_down.addItem(color)
self.buttonLayout = QVBoxLayout()
self.buttonLayout.addWidget(self.OpenDialog)
self.buttonLayout.addWidget(self.drop_down)
self.buttonLayout.addWidget(self.closeWindow)
self.mainWidget = QWidget()
self.mainLayout = QHBoxLayout(self.mainWidget)
self.freeSpace = QWidget()
self.freeSpace.setStyleSheet("background-color: black")
self.mainLayout.setSpacing(10)
self.mainLayout.setContentsMargins(20, 20, 20, 20)
self.mainLayout.addLayout(self.buttonLayout)
self.mainLayout.addWidget(self.freeSpace, 1)
self.setCentralWidget(self.mainWidget)
self.showFullScreen()
# screenWidth, screenHeight = pyautogui.size()
# self.setGeometry(0,0,screenWidth+1, screenHeight)
def openDBox(self):
openImageFile, _ = QFileDialog.getOpenFileName()
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = TestCode()
# main_window.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint | Qt.BypassWindowManagerHint)
main_window.show()
sys.exit(app.exec_())

How do I align centre image horizontally in PyQt5?

I'm working on my college project, I want to align an Image to centre Horizontally, I tried many thing but not find solution. Here is my code:
from PyQt5.QtGui import QPalette, QLinearGradient, QColor, QBrush, QPixmap
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
import sys
from PyQt5 import QtGui
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.acceptDrops()
self.setWindowTitle("Mask Detection")
self.setWindowIcon(QtGui.QIcon('img.png'))
self.setGeometry(0, 0, 400, 300)
self.label = QLabel(self)
self.label.setAlignment(Qt.AlignCenter)
self.pixmap = QPixmap('PBL.png')
self.label.setPixmap(self.pixmap)
self.label.resize(self.pixmap.width(),
self.pixmap.height())
self.show()
App = QApplication(sys.argv)
window = Window()
p = QPalette()
gradient = QLinearGradient(0, 0, 0, 400)
gradient.setColorAt(0.0, QColor(56, 93, 166))
gradient.setColorAt(1.0, QColor(10, 123, 146))
p.setBrush(QPalette.Window, QBrush(gradient))
window.setPalette(p)
sys.exit(App.exec())
The alignment is with respect to the geometry of the element itself, and since the geometry of the QLabel has the same size as the QPixmap then it will not make a difference. The solution is to make the geometry of the QLabel be the same as the window and that can be done by setting it in the centralWidget:
self.setCentralWidget(self.label)

one single scroll bar for two QTextEdit, pyqt4, python

How to make one single scroll bar for two QTextEdit, pyqt4, python. Or how to synchronize two scrollbars of two QTextEdit. For simultaneous scrolling texts.
Pyqt4, python.
Cross-connect the value changed signals of all the scrollbars:
from PyQt4 import QtCore, QtGui
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.edit1 = QtGui.QTextEdit(self)
self.edit2 = QtGui.QTextEdit(self)
layout = QtGui.QHBoxLayout(self)
layout.addWidget(self.edit1)
layout.addWidget(self.edit2)
self.edit1.horizontalScrollBar().valueChanged.connect(
self.edit2.horizontalScrollBar().setValue)
self.edit1.verticalScrollBar().valueChanged.connect(
self.edit2.verticalScrollBar().setValue)
self.edit2.horizontalScrollBar().valueChanged.connect(
self.edit1.horizontalScrollBar().setValue)
self.edit2.verticalScrollBar().valueChanged.connect(
self.edit1.verticalScrollBar().setValue)
text = '\n'.join(name for name in dir(QtCore))
self.edit1.setText(text)
self.edit2.setText(text)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 600, 400)
window.show()
sys.exit(app.exec_())

Resources