How to wrap text around button in Kivy? - python

I have three buttons (one column, three rows) in a GridLayout.
The text on the top of the button is centered but when it is too long it extends past the screen. How do I wrap it? Current code is:
self.add_widget(Button(text="", text_size = (None, self.height), halign = "center", valign = "center"))
for each of the buttons.

Setting
text_size = (None, self.height)
as an arg to the Button constructor does not set up a binding. It just sets the text_size to the values at the moment that the Button __init__() method is executed. So the text_size gets set to (None, 100) and stays that way (the default height of a widget is 100). If you want to actually have such a binding, you must either use the Kivy language, or set up the binding yourself. Something like this:
butt = Button(text="", text_size = self.size, halign = "center", valign = "center")
butt.bind(size=self.resize)
self.add_widget(butt)
def resize(self, butt, new_size):
butt.text_size = new_size

Related

How to use the ScrollView on PC?

I have tried to add a simple scroll view on PC, I define the scroll view like any other widget and then adds its layout and that I then add the widgets.
Here is the code I use:
Window.size = (339, 600)
self.w1 = self
with self.w1.canvas.before:
Color(0.941176, 0.941176, 0.941176, 1)
self.rect = Rectangle(size=self.w1.size, pos=self.w1.pos)
self.w1.bind(pos=self.update_rect, size=self.update_rect)
self.scroll1 = ScrollView(size_hint=(None, 1), size=(Window.width, Window.height),scroll_type = ['bars',"content"])
self.w1.add_widget(self.scroll1)
self.scroll1_layout = RelativeLayout(pos_hint ={'x':0.0, 'y':0.0},size_hint = (0.626844, 1))
self.scroll1.add_widget(self.scroll1_layout)
self.button1 = Button(text = "Button", pos_hint ={'x':0.568182, 'y':0.47585}, size_hint = (1.30682, 0.0545617))
self.scroll1_layout.add_widget(self.button1)
self.button2 = Button(text = "Button", pos_hint ={'x':0.227273, 'y':0.864937}, size_hint = (0.909091, 0.0992844))
self.scroll1_layout.add_widget(self.button2)
How do I make it so that it has a button and below the widget origin. the widget origin is the bottom left of the widget and the bottom below it would not be visible until I scrolled down.
Thank You for any help.

No effects on size_hint , python, kivy

I try to change the size_hint of a button in Python, Kivy, but every value i put there the size of the button remain the same.. for the pos is changing but for the size_hint no, and if i change from pos to pos_hint the button is stuck in the corner of the window and from there i cant change nothing... also i tried to stick the pos of the button on a position where is a text in the photo but every time when i resize the kivy window the button and image are changing theyr position.. how i can solve this probelm ?? THANKSSS !!
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.button import Button
from random import choice
class MyImage(Image):
images = ["Q1.png", "Q2.png", "Q3.png"] # ........
def __init__(self, **kwargs):
super().__init__(**kwargs)
correct = Button(pos=(200, 200), size_hint=(.1, .1), on_release=self.random_image, background_color=(1, 1, 1, 0.2))
self.add_widget(correct)
self.random_image()
def random_image(self, *_):
self.source = choice(self.images)
class RandomQuestionApp(App):
def build(self):
return MyImage()
randomApp = RandomQuestionApp()
RandomQuestionApp().run()
Try size instead of size_hint.
correct = Button(
pos=(200, 200),
size=(100, 100),
on_release=self.random_image,
background_color=(1, 1, 1, 0.2)
)
size : This is for static sizing of widgets and takes two arguments
i.e. (width, height). Default size of the button = (100, 100).
size_hint : This is for dynamic sizing of the button and provide hint
of size. It contains two arguments i.e. width and height it can be
floating values.By default, all widgets have their size_hint=(1, 1).
If there is nothing that influences the button size, your dynamics won't do anything. Size on the other hand would define a fixed size of the button where 100x100 is the default.

PySide2 QTextEdit doesn't adjust to it's own content when using wrapping. (Making chat window)

The PySide2 QTextEdit doesn't change it's own size when the text is placed in.
I'm trying to create something like chat window, where every message - QTextEdit in OnlyRead mode. All the 'messages' placed in QScrollArea. The main goal is to let message-boxes (message-boxeslike on the screen below) adjust their size to content.
wrong working example
I tried this code
https://ru.stackoverflow.com/questions/1408239/Как-сделать-двухсторонний-чат-в-qt-pyqt/1408264#1408264
which has been copy-pasted lots of times. But it doesn't do what i want. It creates a fixed, no resizable QTextEdit message-boxes.
As example what i actually mean, if we have a single-word message, QTextEdit widget must become a single stroke box, with width of the message. If we have a multi-sentences message, QTextEdit widget must become a multi-stroke box (already expanded in height, without the need to scroll it inside), with maximum constant length(which i ll choose).
Next is the example with correct messages displaying
(good example)
In order to implement a self-adjusting message, some precautions are required.
As explained in my answer and comments to the related post, you must consider the complex and delicate relation between the dimensions of a layout and its requirement, which becomes even more complex as a text layout doesn't have a fixed ratio.
The main problem with setting the width based on the text is that it can change the height required to display it, which can cause a recursion, and since the size is based on the current viewport size, the result is that the minimumSizeHint() will always return the smallest possible size after a certain amount of recursive calls.
Considering the above, we must do the following changes to my original code:
the scroll area must always set a maximum width to its message widgets, possibly with a specified margin (for sent/received distinction) whenever the view is resized;
widgets must be added to the layout with an alignment argument;
the minimumSizeHint() must be changed to:
compute the preferred text width (idealWidth() based on the maximum size of the widget;
get the reference height for that text width;
set the text width to the current width;
compare the new document height with the previous one, if they are the same it means that we can use the new width as maximum width for the hint (the text can be shorter), otherwise we use the initial text width based on the maximum size;
Note that there are a couple of differences from the modified code of your link: most importantly, rewriting the stylesheet doesn't make a lot of sense, and setting the margin creates an issue with the value returned by frameWidth() (that's why they subtracted 100 from the document height); that is certainly not a good choice, as the margin should be set within the layout.
class WrapLabel(QtWidgets.QTextEdit):
def __init__(self, text=''):
super().__init__(text)
self.setReadOnly(True)
self.setSizePolicy(QtWidgets.QSizePolicy.Preferred,
QtWidgets.QSizePolicy.Maximum)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.textChanged.connect(self.updateGeometry)
def minimumSizeHint(self):
margin = self.frameWidth() * 2
doc = self.document().clone()
doc.setTextWidth(self.maximumWidth())
idealWidth = doc.idealWidth()
idealHeight = doc.size().height()
doc.setTextWidth(self.viewport().width())
if doc.size().height() == idealHeight:
idealWidth = doc.idealWidth()
return QtCore.QSize(
max(50, idealWidth + margin),
doc.size().height() + margin)
def sizeHint(self):
return self.minimumSizeHint()
def resizeEvent(self, event):
super().resizeEvent(event)
self.updateGeometry()
class ChatTest(QtWidgets.QScrollArea):
def __init__(self):
super().__init__()
self.margin = 100
self.marginRatio = .8
self.messages = []
container = QtWidgets.QWidget()
self.setWidget(container)
self.setWidgetResizable(True)
layout = QtWidgets.QVBoxLayout(container)
layout.addStretch()
self.resize(480, 360)
letters = 'abcdefghijklmnopqrstuvwxyz '
for i in range(1, 11):
msg = ''.join(choice(letters) for i in range(randrange(10, 250)))
QtCore.QTimer.singleShot(500 * i, lambda msg=msg, i=i:
self.addMessage(msg, i & 1))
def addMessage(self, text, sent=False):
message = WrapLabel(text)
message.setStyleSheet('''
WrapLabel {{
border: 1px outset palette(dark);
border-radius: 8px;
background: {};
}}
'''.format(
'#fff8c7' if sent else '#ceffbd')
)
self.messages.append(message)
self.widget().layout().addWidget(message,
alignment=QtCore.Qt.AlignRight if sent else QtCore.Qt.AlignLeft)
QtCore.QTimer.singleShot(0, self.scrollToBottom)
def scrollToBottom(self):
QtWidgets.QApplication.processEvents()
self.verticalScrollBar().setValue(
self.verticalScrollBar().maximum())
def resizeEvent(self, event):
sb = self.verticalScrollBar()
atMaximum = sb.value() == sb.maximum()
maxWidth = max(self.width() * self.marginRatio,
self.width() - self.margin) - sb.sizeHint().width()
for message in self.messages:
message.setMaximumWidth(maxWidth)
super().resizeEvent(event)
if atMaximum:
sb.setValue(sb.maximum())

How to make a label with size_hint in kivy python

I'm trying to do a label with size_hint in a floatlayout but I've realized that doesn't work. I want to make a responsive size of label, because the app wil run in different sizes of screen. I'm doing in kivy language, the code is:
Label:
text: "I'm trying to make a label with size_hint_y"
size_hint_y: 0.6 #doesn't work, always the same size of font
pos_hint: {'center_x':0.5,'center_y':0.36}
#doesn't work, always the same size of font
size_hint_y controls the size of the widget, not the font. Use font_size instead.
I made my font size = the vertical resolution of the screen * the height of the widget * .5. It does not work perfectly, but it seems to work well enough for now.
Since your size_hint = .6, I would try
font_size = (Window.size)[1] * .6 * .5
I also added did not use a KV file. I do not know if that will make a difference.
My code for a similar program looked something like this
I made variables for the size of the widget and the font size
size = (.2, .075)
fontsize = (Window.size)[1] * size * .5
Then to add the widget
self.button = Button(text = "Press Me", size_hint = size, font_size = fontsize)
Hopefully, this helps!

How can I center a label in the center of a QWizardPage?

I have a label:
self.label = QtLabel(self)
that is inside of a VBoxLayout.
That I want to set in the center of a QWizardPage, no matter what size the window becomes. I managed to get it centered horizontally with:
self.label.setAlignment(QtCore.Qt.AlignCenter)
but I cannot seem to get it to center vertically too. I've tried
self.label.setAlignment(QtCore.Qt.AlignVCenter)
and:
self.label.setAlignment(QtCore.Qt.AlignCenter | AlignVCenter)
and a couple of other things that I cannot remember at this moment (I'll edit if I do). After reading this answer it seemed the problem had something to do with setting a min and max size. I tried that, setting MinimumHeight and MaximumHeight to 200. That roughly centered the label but it doesn't adapt to changes in the window's height, only its width.
How can I center this label directly in the middle of my page?
Add your label in between two spacer items. Your vertical layout should also be laid out in its parent widget so it takes full size of the parent.
QSpacerItem* verticalSpacer1 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
label = new QLabel(Form);
label->setAlignment(Qt::AlignCenter);
QSpacerItem* verticalSpacer2 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
verticalLayout->addItem(verticalSpacer1);
verticalLayout->addWidget(label);
verticalLayout->addItem(verticalSpacer2);
If you don't want to set a minimum size policy you could use QWidgets to do something like this:
QWizardPage.__init__(self)
intro_text = "Some text that needs to be centered..."
self.introVBox = QVBoxLayout(self)
self.sizer_top = QWidget()
self.sizer_top.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.sizer_bottom = QWidget()
self.sizer_bottom.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.label = QLabel(self)
self.label.setText(intro_text)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.introVBox.addWidget(self.sizer_top)
self.introVBox.addWidget(self.label)
self.introVBox.addWidget(self.sizer_bottom)
self.setLayout(self.introVBox);

Categories