KIVY python: Slider inside ScrollView - slider

I created a scroll view in which i put some labels and 2 sliders.
The scroll works perfectly, but I can't change the slider's value with my mouse...
Please run this code and see:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.uix.slider import Slider
from kivy.uix.textinput import TextInput
class Home(BoxLayout):
def __init__(self, **kwargs):
super(Home, self).__init__(**kwargs)
self.layout = GridLayout(cols=1, padding=5, spacing=20, size_hint=(1, None))
self.layout.bind(minimum_height=self.layout.setter('height'))
for i in range(50):
if i%25==0:
btn = Slider(min=1, max=10, value=4)
else:
btn = Label(text=str(i), color=(0,0,0,1), size=(32, 32), size_hint=(1, None))
self.layout.add_widget(btn)
self.scrll = ScrollView(size_hint=(1, .6), pos_hint={'center_x': .5, 'center_y': .5}, do_scroll_x=False)
self.scrll.add_widget(self.layout)
self.add_widget(self.scrll)
class MyAppli(App):
def build(self):
Window.clearcolor = (1,1,1,1)
return Home()
if __name__ == '__main__':
MyAppli().run()

Okay when you work with slider you shall redefine the on_touch_down, on_touch_up and on_touch_move method to handle those events:
-main.py :
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.properties import NumericProperty
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.uix.slider import Slider
class Home(BoxLayout):
def __init__(self, **kwargs):
super(Home, self).__init__(**kwargs)
self.b = []
self.layout = GridLayout(cols=1, padding=5, spacing=20, size_hint=(1, None))
self.layout.bind(minimum_height=self.layout.setter('height'))
for i in range(50):
if i % 25 == 0:
self.b.append(MySlider(min=1, max=10, value=4, height=32, size_hint=(1, None)))
else:
self.b.append(Label(text=str(i), color=(0,0,0,1), height=32, size_hint=(1, None)))
self.layout.add_widget(self.b[i])
self.scrll = ScrollView(size_hint=(1, .6), pos_hint={'center_x': .5, 'center_y': .5}, do_scroll_x=False)
self.scrll.add_widget(self.layout)
self.add_widget(self.scrll)
def update(self, *args):
for i in range(50):
if i % 25 == 0:
self.b[i].begin = self.b[i].pos[0]
self.b[i].len = self.b[i].size[0]
class MySlider(Slider):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
super(MySlider, self).on_touch_down(touch)
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
super(MySlider, self).on_touch_up(touch)
def on_touch_move(self, touch):
if self.collide_point(*touch.pos):
super(MySlider, self).on_touch_move(touch)
class MyAppli(App):
def build(self):
Window.clearcolor = (1,1,1,1)
return Home()
if __name__ == '__main__':
MyAppli().run()
-some outputs :
I hope this helps !

Related

Indicating that a QOpenGLWidget widget is to have a translucent background does not appear to work

There is no effect when I set the WA_TranslucentBackground attribute on a widget (derived from QOpenGLWidget). I have to set the attribute on the main window instead, which doesn't seem right: the documentation clearly states that the attribute applies to the widget itself:
Indicates that the widget should have a translucent background, i.e.,
any non-opaque regions of the widgets will be translucent because the
widget will have an alpha channel
What is the correct way to make the widget itself have a translucent background? Here is the code:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QOpenGLWidget
from PyQt5.QtCore import Qt, QPointF, QLineF
from PyQt5.QtGui import QColor, QPen, QPainter, QPaintEvent
class LineWidget(QOpenGLWidget):
def __init__(self, parent, start : QPointF, end : QPointF, colour : str = 'black'):
super(LineWidget, self).__init__(parent)
self.colour = colour
self.line = QLineF(start, end)
# self.setAttribute(Qt.WA_TranslucentBackground)
def paintEvent(self, a0: QPaintEvent) -> None:
painter = QPainter(self)
painter.begin(self)
painter.setPen(QPen(QColor(self.colour), 5))
painter.drawLine(self.line)
painter.end()
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.lineWidget = LineWidget(self, QPointF(0, 0), QPointF(400, 400), 'red')
self.setCentralWidget(self.lineWidget)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

Problem with changing the value of main button in KivyMD Menu

I have created a KivyMD Menu. When I click on the main Button, the menu is opening without a problem. However when I click on a menu button the value of the main button is not changing. Nothing happens. I thought the code is sufficient to achieve it. Does anyone know a solution? Thank you in advance!
py file:
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu
Window.size = (400, 800)
class homescreen(Screen):
pass
GUI = Builder.load_file("main.kv")
class MainApp(MDApp, homescreen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.homescreen = Builder.load_string("homescreen")
menu_items = [{"icon": "git", "text": f"Item {i}"} for i in range(5)]
self.menu = MDDropdownMenu(
caller=self.ids.drop_item,
items=menu_items,
#position="center",
width_mult=4,
)
self.menu.bind(on_release=self.set_item)
def set_item(self, instance_menu, instance_menu_item):
self.ids.drop_item.set_item(instance_menu_item.text)
self.menu.dismiss()
def build(self):
return self.homescreen
if __name__ == "__main__":
MainApp().run()
main.kv:
<homescreen>:
MDDropDownItem:
id: drop_item
pos_hint: {'center_x': .5, 'center_y': .5}
text: "Select"
on_release: app.menu.open()
Here is your improved code
py file:
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu
Window.size = (400, 800)
class homescreen(Screen):
pass
GUI = Builder.load_file("main.kv")
class MainApp(homescreen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.homescreen = Builder.load_string("homescreen")
menu_items = [{"icon": "git", "text": f"Item {i}"} for i in range(5)]
self.menu = MDDropdownMenu(
caller=self.ids.drop_item,
items=menu_items,
callback=self.set_item,
width_mult=4,
)
def set_item(self, instance_menu_item):
self.ids.drop_item.text = instance_menu_item.text
self.menu.dismiss()
def build(self):
return self.homescreen
class app(MDApp):
def build(self):
return MainApp()
if __name__ == "__main__":
app().run()
main.ky
<homescreen>:
MDDropDownItem:
id: drop_item
pos_hint: {'center_x': .5, 'center_y': .5}
text: "Select"
on_release: root.menu.open()

Calling method from other class

I'm very new to PyQt5, and I'm trying to make an interactive gui for plotting of data. However, this problem may well be completely unrelated to PyQt5 and more a problem with my understanding of object oriented programming in general.
I have a MainWindow class, a SupportClass1 and a SupportClass2. When I make an instance of SupportClass1, I want to call the method DoSomething in the MainWindow class by referring to the object window, but I get the error message NameError: name 'window' is not defined.
I have no problems creating a method in the SupportClass2 and calling that from the MainWindow class so I get the impression that I have not instantiated the MainWindow class correctly which I don't understand as I thought I had defined window as an instace of the MainWindow class.
Can anyone help me understand what is wrong in my logic and how to solve this problem?
from PyQt5 import QtWidgets, QtCore
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys
import os
from random import randint
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.graphWidget = pg.PlotWidget()
self.x = list(range(100))
self.y = [randint(0,100) for _ in range(100)]
self.graphWidget.setBackground('w')
pen = pg.mkPen(color=(255, 0, 0))
self.data_line = self.graphWidget.plot(self.x, self.y, pen=pen)
self.button = QPushButton('Test')
self.button.clicked.connect(self.InstantiateSupportClasses)
self.gui_box = QVBoxLayout()
self.gui_box.addWidget(self.graphWidget)
self.gui_box.addWidget(self.button)
self.setLayout(self.gui_box)
self.setGeometry(300, 300, 300, 150)
self.setWindowTitle('Test application')
self.show()
def InstantiateSupportClasses(self):
supp_class2 = SupportClass2()
print(supp_class2.GetVariable())
supp_class1 = SupportClass1()
def DoSomething(self):
print('I did something!')
class SupportClass1():
def __init__(self):
window.DoSomething
class SupportClass2():
def __init__(self):
self.some_variable = 5
def GetVariable(self):
return self.some_variable
def main():
app = QApplication(sys.argv)
app.setStyle('Fusion')
window = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()```
I see that you are using the "window" object from the "SupportClass1" class.
but that class does not recognize this object one solution is to insert that object to the "SupportClass1()"
from PyQt5 import QtWidgets, QtCore
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys
import os
from random import randint
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.graphWidget = pg.PlotWidget()
self.x = list(range(100))
self.y = [randint(0,100) for _ in range(100)]
self.graphWidget.setBackground('w')
pen = pg.mkPen(color=(255, 0, 0))
self.data_line = self.graphWidget.plot(self.x, self.y, pen=pen)
self.button = QPushButton('Test')
self.button.clicked.connect(self.InstantiateSupportClasses)
self.gui_box = QVBoxLayout()
self.gui_box.addWidget(self.graphWidget)
self.gui_box.addWidget(self.button)
self.setLayout(self.gui_box)
self.setGeometry(300, 300, 300, 150)
self.setWindowTitle('Test application')
self.show()
def InstantiateSupportClasses(self):
supp_class2 = SupportClass2()
print(supp_class2.GetVariable())
supp_class1 = SupportClass1(self)
def DoSomething(self):
print('I did something!')
class SupportClass1():
def __init__(self, window):
window.DoSomething()
class SupportClass2():
def __init__(self):
self.some_variable = 5
def GetVariable(self):
return self.some_variable
def main():
app = QApplication(sys.argv)
app.setStyle('Fusion')
window = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Home button in Matplotlib 2.1.0 navigation toolbar embeded in pyqt5 window, it no longer works correctly

I embedded a matplotlib in a window maked in qtdesigner, pyqt5. I have 3 files
The window:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MplMainWindow(object):
def setupUi(self, MplMainWindow):
MplMainWindow.setObjectName("MplMainWindow")
MplMainWindow.resize(628, 416)
self.centralwidget = QtWidgets.QWidget(MplMainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName("gridLayout_2")
self.mpl = MplWidgetTest(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mpl.sizePolicy().hasHeightForWidth())
self.mpl.setSizePolicy(sizePolicy)
self.mpl.setObjectName("mpl")
self.gridLayout_2.addWidget(self.mpl, 0, 0, 1, 1)
self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox.setMaximumSize(QtCore.QSize(95, 16777215))
self.groupBox.setObjectName("groupBox")
self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
self.gridLayout.setObjectName("gridLayout")
self.buttonDrawDate = QtWidgets.QPushButton(self.groupBox)
self.buttonDrawDate.setMaximumSize(QtCore.QSize(75, 16777215))
self.buttonDrawDate.setObjectName("buttonDrawDate")
self.gridLayout.addWidget(self.buttonDrawDate, 0, 0, 1, 1)
self.buttonErase = QtWidgets.QPushButton(self.groupBox)
self.buttonErase.setMaximumSize(QtCore.QSize(75, 16777215))
self.buttonErase.setObjectName("buttonErase")
self.gridLayout.addWidget(self.buttonErase, 1, 0, 1, 1)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem, 2, 0, 1, 1)
self.gridLayout_2.addWidget(self.groupBox, 0, 1, 1, 1)
MplMainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MplMainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 628, 21))
self.menubar.setObjectName("menubar")
MplMainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MplMainWindow)
self.statusbar.setObjectName("statusbar")
MplMainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MplMainWindow)
QtCore.QMetaObject.connectSlotsByName(MplMainWindow)
def retranslateUi(self, MplMainWindow):
_translate = QtCore.QCoreApplication.translate
MplMainWindow.setWindowTitle(_translate("MplMainWindow", "MainWindow"))
self.groupBox.setTitle(_translate("MplMainWindow", "GroupBox"))
self.buttonDrawDate.setText(_translate("MplMainWindow", "Draw"))
self.buttonErase.setText(_translate("MplMainWindow", "Erase"))
from mplwidgettest import MplWidgetTest
The Matplot widget class:
from PyQt5.QtWidgets import QSizePolicy, QWidget, QVBoxLayout
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
class MplCanvas(FigureCanvas):
"""Class to represent the FigureCanvas widget"""
def __init__(self):
# setup Matplotlib Figure and Axis
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
# initialization of the canvas
FigureCanvas.__init__(self, self.fig)
# we define the widget as expandable
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
# notify the system of updated policy
FigureCanvas.updateGeometry(self)
class MplWidgetTest(QWidget):
"""Widget defined in Qt Designer"""
def __init__(self, parent = None):
# initialization of Qt MainWindow widget
QWidget.__init__(self, parent)
# set the canvas to the Matplotlib widget
self.canvas = MplCanvas()
# create a NavigatioToolbar
self.ntb=NavigationToolbar(self.canvas,self)
# create a vertical box layout
self.vbl = QVBoxLayout()
# add mpl widget to vertical box
self.vbl.addWidget(self.canvas)
# add NavigationToolBar to vertical box
self.vbl.addWidget(self.ntb)
# set the layout to th vertical box
self.setLayout(self.vbl)
And the main file that call others:
import sys
from IHMDrawDates import Ui_MplMainWindow
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget
import numpy as np
import datetime
class DesignerMainWindow(QMainWindow, Ui_MplMainWindow):
def __init__(self, parent = None):
super(DesignerMainWindow, self).__init__(parent)
self.setupUi(self)
# connect the signals with the slots
self.buttonDrawDate.clicked.connect(self.drawDate)
self.buttonErase.clicked.connect(self.eraseDate)
def drawDate(self):
# base = datetime.datetime(2018, 1, 1)
# x = np.array([base + datetime.timedelta(hours=i) for i in range(24)])
# y = np.random.rand(len(x))
x = np.arange(0,100,0.1)
y = np.sin(x)
self.mpl.canvas.ax.plot(x,y)
self.mpl.canvas.ax.relim()
self.mpl.canvas.ax.autoscale(True)
self.mpl.canvas.draw()
def eraseDate(self):
self.mpl.canvas.ax.clear()
self.mpl.canvas.draw()
if __name__ == '__main__':
app=0
app = QApplication(sys.argv)
dmw = DesignerMainWindow()
# show it
dmw.show()
sys.exit(app.exec_())
After update to matplotlib 2.1.0, the home button does not work correctly. It always return to the inicial clean axes. Example:
1.-Before click in drawing button:
2.-Click in draw button:
3.-Click in zoom:
4.-Click in home:
before the update, pressing the button HOME it returned to the image number 2, now with matplotlib 2.1.0 it returned to image 4. Any idea.
When I add:
def drawDate(self):
x = np.arange(0,100,0.1)
y = np.sin(x)
self.mpl.canvas.ax.plot(x,y)
self.mpl.canvas.ax.relim()
self.mpl.canvas.ax.autoscale(True)
self.mpl.ntb.update()
self.mpl.canvas.draw()
def eraseDate(self):
self.mpl.canvas.ax.clear()
self.mpl.ntb.update()
self.mpl.canvas.draw()
Then occurs:
I guess the answer to this question is given in this post, just for Tkinter, instead of PyQt:
NagivationToolbar fails when updating in Tkinter canvas
The home button restores the initial state of the plot, which is usually the desired functionality of a home button.
Here you apparently want it to restore the state of the plot, after the button has clicked. This would be done by calling the toolbar's update() method.
In this case you'd add
self.mpl.ntb.update()
inside the drawDate method.
The method could then look like
def drawDate(self):
x = np.arange(0,100,0.1)
y = np.sin(x)
self.mpl.canvas.ax.plot(x,y)
self.mpl.canvas.ax.relim()
self.mpl.canvas.ax.autoscale(True)
self.mpl.ntb.update() # <-- add this
#self.mpl.ntb.push_current() # and possibly this(?)
self.mpl.canvas.draw()
def eraseDate(self):
self.mpl.canvas.ax.clear()
self.mpl.ntb.update() # <-- add this
#self.mpl.ntb.push_current() # and possibly this(?)
self.mpl.canvas.draw()

pyqt5 videowidget not showing in layout

I am writing a program with pyqt5 where pressing a button first cycles through some pictures then cycles through some videos.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
import argparse
import sys
class MainWindow(QMainWindow):
def __init__(self,args):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = CentralWidget(args)
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
QCoreApplication.instance().quit()
self.centralwidget.startvid()
class CentralWidget(QWidget):
def __init__(self,args):
super(CentralWidget, self).__init__()
self.layout = QVBoxLayout()
self.layout.setAlignment(Qt.AlignCenter)
self.setLayout(self.layout)
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.vw = QVideoWidget()
self.player.setVideoOutput(self.vw)
def startvid(self):
self.layout.addWidget(self.vw)
url= QUrl.fromLocalFile(glob.glob("videos/*")[0])
content= QMediaContent(url)
self.player.setMedia(content)
self.player.setVideoOutput(self.vw)
self.player.play()
if __name__== "__main__":
parser = argparse.ArgumentParser()
#~ parser.add_argument("-nb","--nobox",action="store_true", help="do not wait for the box connection")
args = parser.parse_args()
app = QApplication(sys.argv)
mainwindow = MainWindow(args)
#~ mainwindow.showFullScreen()
mainwindow.show()
sys.exit(app.exec_())
I tried to paste the minimal code. The thing is, I press the button nothing shows, although I used examples like this one PyQt5 - Can't play video using QVideoWidget to test if playing the video is ok, and these work. It's as if it is not adding the widget to the layout or something. Any idea what might be wrong?
I had to use QGraphicsView to achieve what I wanted, here is a fix:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = VideoPlayer()
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
self.centralwidget.phaseQuit(2)
self.centralwidget.play()
class VideoPlayer(QWidget):
def __init__(self, parent=None):
super(VideoPlayer, self).__init__(parent)
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.videoItem = QGraphicsVideoItem()
self.videoItem.setSize(QSizeF(640, 480))
scene = QGraphicsScene(self)
graphicsView = QGraphicsView(scene)
scene.addItem(self.videoItem)
layout = QVBoxLayout()
layout.addWidget(graphicsView)
self.setLayout(layout)
self.mediaPlayer.setVideoOutput(self.videoItem)
self.counter = 0
def play(self):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
pass
else:
self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(glob.glob("videos/*")[self.counter])))
self.mediaPlayer.play()
self.counter += 1
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
player = MainWindow()
player.show()
sys.exit(app.exec_())