I tried .setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) which works nicely but requires user to move mouse to the scroll bar and use it to experience the smooth scroll but the mouse wheel works the old way with jumpy scrolling, i wonder if there a way to make the scrolling behave the same when using the mouse wheel ?
You should use self.widget.verticalScrollBar().setSingleStep(step).
QTableWidget inherits QTableView, which inherits QAbstractItemView, which inherits QAbstractScrollArea, which has method verticalScrollBar(), which brings us to the QScrollBar Class that inherits QAbstractSlider, which finally has setSingleStep(step) method (maybe there is shorter path?).
Here's the complete code:
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Window(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setWindowTitle("Scrolling QTableWidget smoothly BY MOUSE WHEEL")
label = QLabel("singleStep:")
self.spinbox = QSpinBox()
self.spinbox.setValue(1)
self.spinbox.setMinimum(1)
self.spinbox.setMaximum(200)
self.spinbox.valueChanged.connect(self.on_value_changed)
self.widget = QTableWidget(100, 5)
for i in range(100):
for j in range(5):
self.widget.setItem(i, j, QTableWidgetItem(str(i+j)))
self.widget.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
#self.widget.verticalScrollBar().setSingleStep(1)
self.set_single_step()
spinbox_layout = QHBoxLayout()
spinbox_layout.addStretch()
spinbox_layout.addWidget(label)
spinbox_layout.addWidget(self.spinbox)
layout = QVBoxLayout()
layout.addLayout(spinbox_layout)
layout.addWidget(self.widget)
self.setLayout(layout)
def on_value_changed(self, step):
self.set_single_step()
def set_single_step(self):
self.widget.verticalScrollBar().setSingleStep(self.spinbox.value())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.resize(800, 600)
window.show()
sys.exit(app.exec())
You can increase/decrease step in spinbox to see how it behaves. I hope that is what you asked for.
Related
So I want to grab the QFrame and scroll it, so I'm using mouse-move-event to do it, but the problem I have is the event triggers even when I click outside the Frame that I set Mouse Tracking on. So I thought of stopping at least the mouse-Move-Event early at mouse-press-event, but the problem is the focusWidget method always returns the scroll area, so I can't filter out the other widgets, and the ignore method doesn't stop the chain of events execution.
Code Demo:
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget,
QVBoxLayout, QFrame, QScrollArea)
class Window(QMainWindow):
def __init__(self):
super(Window, self).__init__()
"""supposed to stop the events' chain when it's not the scrolling frame"""
def mousePressEvent(self, event):
if QApplication.focusWidget()!=scroll:
print("ignore")
event.ignore()
def mouseMoveEvent(self, event):
print("move")
app = QApplication(sys.argv)
layout = QVBoxLayout()
b_widget=QFrame()
b_widget.setStyleSheet("background-color: blue")
b_widget.setMinimumSize(100, 50)
r_widget=QFrame()
r_widget.setStyleSheet("background-color: red")
r_widget.setMinimumSize(100, 50)
g_widget=QFrame()
g_widget.setStyleSheet("background-color: green")
g_widget.setMinimumSize(1000, 1000)
"""activating mouse tracking on the scrolling frame"""
g_widget.setMouseTracking(True)
scroll=QScrollArea()
scroll.setWidget(g_widget)
layout.addWidget(r_widget)
layout.addWidget(b_widget)
layout.addWidget(scroll)
widget = QWidget()
widget.setLayout(layout)
main=Window()
main.setCentralWidget(widget)
main.show()
app.exec()
Thank you for your help.
good day, I wonder if someone could tell me why I end up with the following lines around the edge of my GUI.
The skeleton code is below which replicates the problem. I've tried adding stylesheets and QT alignment but to no avail. I think the issue could be with the QScrollArea(). I would love any help as this one has me stumped. Thank you
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.main_window()
def main_window(self):
self.setGeometry(0, 0, 500, 500)
self.grid = QGridLayout()
vbox = QVBoxLayout()
wrapper_widget = QWidget()
wrapper_widget.setLayout(self.grid)
# Bars
scroll = QScrollArea()
scroll.setWidget(wrapper_widget)
master_widget = QWidget()
vbox.addWidget(scroll)
master_widget.setLayout(vbox)
self.setCentralWidget(master_widget)
# Show
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec())
I want to have a central Widget with a grid layout containing multiple other widgets .
the problem is that the central widget is not showing on QMainWindow even after using setCentralWidget function .
here is the code that is not working, i can't find the error (edit: there was no exceptions raised, just the fact i couldn't see the widgets)
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QGridLayout
class Board(QWidget):
def __init__(self):
super().__init__()
Clock(QWidget):
def __init__(self):
super().__init__()
class MainGrid(QWidget):
def __init__(self):
super().__init__()
self.initGrid()
def initGrid(self):
grid= QGridLayout()
test = QLabel('test')
board = Board()
clock = Clock()
board.setStyleSheet('background-color: pink')
clock.setStyleSheet('background-color: blue')
grid.addWidget(board, 2, 1, 10, 10)
grid.addWidget(clock, 13, 4, 3, 3)
self.setLayout(grid)
class MainWin(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
centralGrid = MainGrid()
centralGrid.setStyleSheet('background-color: red')
centralGrid.sizeHint()
self.setCentralWidget(centralGrid)
self.setGeometry(200, 100, 1000, 600)
self.setWindowTitle('Simple Checkers')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MainWin()
sys.exit(app.exec_())
edit: thanks to scheff answer i think i found where i went wrong.
to visualize the widgets i changed their backgrounds using setStyleSheet function, on Qt Documentation :
Note: If you subclass a custom widget from QWidget, then in order to use the StyleSheets you need to provide a paintEvent to the custom widget :
as for the test label i used it for further testing but forgot to add it to the grid layout which added even more confusion .
Unfortunately, the OP claimed that
the problem is that the central widget is not showing on QMainWindow even after using setCentralWidget function .
without elaborating in detail.
I had a rough look onto the source and came to the conclusion that
widgets have been added to layout
layout is set to widget
the widget has been set to QMainWindow.
So far so fine.
Then I copied the complete source of OP to my local box.
To make it running I had to add/modify a variety of things:
All Qt imports were missing. I added
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
For sys.argv (in app = QApplication(sys.argv)), import sys is needed as well.
The widgets Board and Clock were missing.
#board = Board()
#clock = Clock()
clock = QLabel('Clock')
#board.setStyleSheet('background-color: pink')
The test = QLabel('test') wasn't added to the grid layout.
grid.addWidget(test, 2, 1, 10, 10)
After having fixed all of this, the (modified) source was this:
#!/usr/bin/python3
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MainGrid(QWidget):
def __init__(self):
super().__init__()
self.initGrid()
def initGrid(self):
grid= QGridLayout()
test = QLabel('test')
#board = Board()
#clock = Clock()
clock = QLabel('Clock')
#board.setStyleSheet('background-color: pink')
test.setStyleSheet('background-color: pink')
clock.setStyleSheet('background-color: blue')
grid.addWidget(test, 2, 1, 10, 10)
grid.addWidget(clock, 13, 4, 3, 3)
self.setLayout(grid)
class MainWin(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
centralGrid = MainGrid()
centralGrid.setStyleSheet('background-color: red')
centralGrid.sizeHint()
self.setCentralWidget(centralGrid)
self.setGeometry(200, 100, 1000, 600)
self.setWindowTitle('Simple Checkers')
self.show()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
gui = MainWin()
sys.exit(app.exec_())
Note:
I added the "hut" in the first line
#!/usr/bin/python3
for my own convenience.
Then I ran it in cygwin64 (because I only had Windows 10 with cygwin at hand):
$ chmod a+x testQMainWindowCentralWidget.py
$ ./testQMainWindowCentralWidget.py
and got:
Now, the QMainWindow.setCentralWidget() works as expected.
I don't know which issues the OP actually ran in.
I'm not sure whether the exposed code of OP was the exact copy/paste and the missing details were the actual source of OP's problems.
When I tried to make it running I carefully considered the trace-backs I got in the first attempts and fixed the bugs step-by-step respectively until I got the above result.
I have this code:
class Window(QWidget):
def __init__(self):
super().__init__()
def init_gui(self):
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.new1()
self.new2()
self.showMaximized()
def create_scroll_area(self):
scroll_area = QScrollArea()
widget = QWidget()
scroll_area.setWidget(widget)
layout = QVBoxLayout()
widget.setLayout(layout)
button = QPushButton("Ahoj")
layout.addWidget(button)
self.layout.addLayout(layout)
def new1(self):
self.create_scroll_area()
def new2(self):
self.create_scroll_area()
I get this error message:
QLayout::addChildLayout: layout "" already has a parent
What's wrong?
Who is layout's parent? Widget? I also tried self.widget instead of widget and it still does not work.
Please try this code.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent=None)
self.init_gui()
def init_gui(self):
self.create_scroll_area()
self.showMaximized()
def create_scroll_area(self):
scroll_area = QScrollArea()
widget = QWidget()
layout = QVBoxLayout()
button = QPushButton("Ahoj")
layout.addWidget(button)
widget.setLayout(layout)
scroll_area.setWidget(widget)
self.setLayout(layout)
def main():
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Let's revise from A to Z.
1 to write self.init_gui() in __init__ constructor.
If you don't do it, you can't execute init_gui method at the first time.
2.setLayout() or setWidget() should be written at the last place at least.
In python, we prepare the things we want to show, and set them on the mainwidget, and show them at the last time.
3.please pay attention to self.layout name.
Widget has originally setLayout() method. and layout() method.
If you make self.layout = ***, you crush the original method of QWidget.
4. it may as well delete new1 and new2 method.
please call them directly.
5. please look create_scroll_area method.
You make three widget.QScrollArea,QWidget,QPushButton.
and make a layout object.and you set the layout into QWidget.
But you set the QWidget before the widget set the layout.
It is not good order for coding.
You make QPushButton but the button doesn't belong to any widget.
Because you set the button on the self.layout certainly, but if you want to show it, you must setLayout(self.layout) at the last position.
Given the sample code below, when clicking on the button "Bar", according to my experience, at least 1 in 10 clicks produces 2 newly opened widgets instead of one. This seems to occur only, if the new widget is opened on top of (completely covers) the widget with the button. Any ideas what is happening here?
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from PyQt5.Qt import QHBoxLayout
class foo(QWidget):
def baz(self):
w = QWidget()
w.show()
self.widgets.append(w)
print(len(self.widgets))
def __init__(self):
super().__init__()
self.widgets = []
lo = QHBoxLayout()
b = QPushButton("Bar")
b.pressed.connect(self.baz)
lo.addWidget(b)
self.setLayout(lo)
app = QApplication([])
w = foo()
w.show()
app.exec_()