11.1
Is anyone knows how to disable the bounce scroll effect when going up in a scrollview ? I've done a scrollview with 100 buttons to test and when I reach the top by finger scrolling, and I stop scrolling, kivy force me to bounce to the 4th button, i would like him to stop to the first button. Do you know how ? Thanks
Here is my code :
import kivy
kivy.require('1.11.1')
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivy.app import runTouchApp
from kivy.app import App
from kivy.effects.scroll import ScrollEffect
from kivy.effects.dampedscroll import DampedScrollEffect
from kivy.properties import NumericProperty
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
for i in range(100):
btn = Button(text=str(i), size_hint_y= None, height=40)
layout.add_widget(btn)
root = ScrollView(size_hint=(1, None),\
size=(Window.width, Window.height),\
bar_width = 10, bar_color= (0,1,0,1),\
scroll_type = ['bars', 'content'],\
effect_cls = 'ScrollEffect'\
)
root.add_widget(layout)
print(root.effect_y)
runTouchApp(root)
Set the size_hint_y of layout to a value bigger than on where it cover all you items in you layout (e.g. 3)
see: Problem with Kivy when trying to scrolldown vertical ScrollView with an horizontal ScrollView inside
root = ScrollView(size_hint=(3, None)
Related
I am building a small diary that includes pictures. I want to arrange those pictures in a single column. When I run the code below, the first picture appears. Pressing Enter, the second picture appears but the previous one disappears and so on until the last picture.
Notice that the 'Press Enter to continue' will not be part of the code. It is there to trigger the posting of the picture. So does the Print(image). It shows the files being processed.
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter import Frame, Menu
from PIL import Image, ImageTk
import os
root = tk.Tk()
root.geometry('750x1000')
root.resizable(0,0)
root.columnconfigure(0, weight=5)
root.columnconfigure(1, weight=5)
root.columnconfigure(2, weight=5)
photo_list = []
photo_list = ['zendo1.png','hadock2.png','moon.png','sun.png','sailboat-sunset.png']
n=0
i=0
j=0
while n < 5:
img=Image.open(photo_list[n])
img= img.resize((150,150),Image.ANTIALIAS)
image=img
photoImg = ImageTk.PhotoImage(image)
photo_label= Label(root, image = photoImg)
print (image)
photo_label.grid(row=i, column=j)
verif_step = input("Please Press Enter to Continue ")
i=i+1
#j=j+1
n += 1
root.mainloop()
I tried with 'While' and 'For', plus looking up previous posts dealing with the same issue. But no cigar...
I'm trying to center a QLabel showing a pixmap inside a QWidget both horizontally and vertically, but for some reason, this seems impossible. I have read many similar questions, and it seems they all comes down to specifying the alignment when adding the label to the layout. Well, I'm doing that and still it's aligning to the top left corner. Can someone please help me center my darn QLabel already? :)
main.py
import sys
from PyQt5.QtWidgets import QApplication
from mainwindow import MainWindow
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
mainwindow.py
from PyQt5.QtGui import QGuiApplication, QWheelEvent
from PyQt5.QtWidgets import QMainWindow
from imagewidget import ImageWidget
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.resize(QGuiApplication.primaryScreen().availableSize() * 3 / 5)
self.image_widget = ImageWidget()
self.setCentralWidget(self.image_widget)
def wheelEvent(self, event: QWheelEvent) -> None:
angleDelta = event.angleDelta().y()
if angleDelta >= 0:
self.image_widget.zoomIn()
else:
self.image_widget.zoomOut()
imagewidget.py
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QPalette
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QSizePolicy, QPushButton
class ImageWidget(QWidget):
def __init__(self):
super().__init__()
self.scale_factor = 1.0
self.label = QLabel()
self.label.setAlignment(Qt.AlignVCenter)
self.label.setPixmap(QPixmap("image.png")) # Loads local test image
self.label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.label.setScaledContents(True)
self.layout = QVBoxLayout()
self.layout.addWidget(self.label, Qt.AlignCenter) # Why does this not align the label to the center of the layout?
self.setLayout(self.layout)
def zoomIn(self):
self.scale_factor *= 1.1
self.resizeUsingScaleFactor()
def zoomOut(self):
self.scale_factor /= 1.1
self.resizeUsingScaleFactor()
def getImageSize(self):
return self.label.pixmap().size()
def resizeUsingScaleFactor(self):
self.label.resize(self.getImageSize() * self.scale_factor)
When you resize a widget it doesn't adjust its position, it just resize it. All widgets set their geometry based on the origin point (the top left corner), if you use resize the origin point will always remain the same.
Since you are using a layout, you should leave the positioning to the layout (which you are also preventing since you're using the Ignore size policy, which is a problem in these cases. Also note that you are using the alignment as the second argument for addWidget, but its signature is addWidget(widget, stretch=0, alignment=Qt.Alignment()), so you should use the correct keyword.
The solution is to use setFixedSize instead, which will ensure that the layout takes care of the correct alignment once it has been notified about the new fixed size (which does not happen when you use resize).
class ImageWidget(QWidget):
def __init__(self):
super().__init__()
self.scale_factor = 1.0
self.label = QLabel()
# no need for this
# self.label.setAlignment(Qt.AlignCenter)
# don't do this
# self.label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.label.setPixmap(QPixmap("image.png")) # Loads local test image
self.label.setScaledContents(True)
self.layout = QVBoxLayout()
self.layout.addWidget(self.label, alignment=Qt.AlignCenter)
self.setLayout(self.layout)
# ...
def resizeUsingScaleFactor(self):
self.label.setFixedSize(self.getImageSize() * self.scale_factor)
When using a QComboBox in PySide2 the popup menu seems to initially start about 10 pixels or so to the left until its finished animating down at which point it pops (about) 10 pixels to the right into the correct position.
How can I fix this? Or am I able to disable the animation so the menu just opens without animating? And am I able to control the animation time for the popup?
Here are two screenshots, the top one is while the combobox dropdown is animating down and the bottom one is after the dropdown is open:
Here's the simple example code use to produce the combobox above:
from PySide2 import QtCore, QtWidgets
import sys
class MyDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(MyDialog, self).__init__(parent)
self.setWindowTitle('Modal Dialogs')
self.setMinimumSize(300,80)
# remove help icon (question mark) from window
self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)
# create widgets, layouts and connections (signals and slots)
self.create_widgets()
self.create_layouts()
self.create_connections()
def create_widgets(self):
self.combo = QtWidgets.QComboBox()
self.combo.addItems(['one','two','three'])
def create_layouts(self):
# self must be passed to the main_layout so it is parented to the dialog instance
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.addWidget(self.combo)
def create_connections(self):
pass
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
my_dialog = MyDialog()
my_dialog.show() # Show the UI
sys.exit(app.exec_())
I am having trouble with making a picture slideshow that is operated with python and executed with kivy.
I am using asynch but I want to make the slideshow so that I open the photo and then when I click with the right it goes forward, but then if the mouse gets clicked on the left, then it goes to the previous page (picture).
Thanks for the help.
You can remove the comment# from the buttons and move left/right methods if you want but I think the carousel direction feature solves that problem. Mind you, I am a newbie so this is just my way of helping out. I figured I'll help some else since I have gotten a lot of help here. Thanks
from kivy.app import App
from kivy.loader import Loader
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.clock import Clock
from kivy.properties import *
from kivy.uix.image import AsyncImage
from kivy.uix.gridlayout import GridLayout
from kivy.uix.carousel import Carousel
from kivy.uix.button import Button
Builder.load_string('''
<MyWidget>:
carousel: carousel
cols: 1
Button:
pos_hint: {"center_x":0.5, "center_y":0.1}
size_hint: .3,.1
font_size: 35
text: str(root.on_off)
on_release: root.start_slide()
Carousel:
pos_hint: {"center_x":0.5, "center_y":0.9}
id: carousel
direction: 'right'
loop: True
index: 0
''')
class MyWidget(GridLayout):
on_off = StringProperty('Start')
slide_count = NumericProperty(11)
def __init__(self, **kwargs):
super(MyWidget, self).__init__()
self.carousel = Carousel(direction='right')
self.add_widget(self.carousel)
for i in range(self.slide_count):
src = "http://placehold.it/480x270.png&text=slide-%d&.png" % i
image = AsyncImage(source=src, allow_stretch=True)
self.carousel.add_widget(image)
#self.start_slide()### Uncomment this to start slideshow when the app starts
def start_slide(self, *args):
if self.on_off == 'Start':
self.on_off = 'Stop'
self.clock = Clock.schedule_interval(self.slide_next, 3) ##move right every 3 seconds
return
if self.on_off == 'Stop':
self.on_off = 'Start'
Clock.unschedule(self.clock)
self.carousel.index = 0
def slide_next(self, *args):
if self.carousel.index == (self.slide_count - 1):
self.carousel.index = 0### This keeps the loops intact
#### if you want to end the slideshow at the last image, use 'Clock.unschedule(self.clock)' instead
return
self.carousel.load_next()
class SlideShowApp(App):
def build(self):
mywidget = MyWidget()
return mywidget
if __name__ == '__main__':
SlideShowApp().run()
Hope this is what you needed
Here is my code:
from tkinter import *
import textwrap
GUI = Tk()
note_frame = Frame(GUI)
note_frame.grid(row=0, column=0)
note_scrollbar = Scrollbar(note_frame)
note_scrollbar.pack(side=RIGHT, fill=Y)
note_container = Canvas(note_frame, yscrollcommand = note_scrollbar.set)
note_container.pack()
note_scrollbar.config(command=note_container.yview)
def configure_note_container(event):
note_container.config(scrollregion=note_container.bbox("all"),
width=200, height=200)
note_list = Frame(note_container, width=200, height=200)
note_container.create_window((0,0), window=note_list, anchor='nw')
note_list.bind("<Configure>", configure_note_container)
for x in range(100):
exec(textwrap.dedent(
"""
label_{0} = Label(note_list, text='{0}', bg="white")
label_{0}.grid(column=0, row={0})
""".format(x)))
GUI.mainloop()
I am trying to get the labels to stretch out to fill the X width of the grid cell within the frame (which is within a canvas so that I can use a scrollbar), but I don't know how to do it - when the note_container gets configured, it seems to cancel out any adjustment of size. grid_propagate doesn't seem to work either.
Any help is appreciated. thanks.