Qt how to break the LabelText of QInputDialog - qt

Here is my example code:
QInputDialog* inDialog = new QInputDialog();
inDialog->setMaximumWidth(100);
inDialog->setLabelText(QString("long and very long......you can say very long"));
The input box showing really long (as long as the string), I was expected the way to set word-wrap for the LabelText, but it seem QInputDialog has no method for that!!!
What can I do now? Write my own InputDialog class? Oh no...!
I hope there is a better way for it!

I would do it myself, like this for example :
QString s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut" ;
QString wrapped ;
if(s.length()>35)
{
wrapped = s.left(15) + QString(".....") + s.right(15) ;
}
else
{
wrapped = s ;
}
inDialog->setLabelText(wrapped) ;

I'm just starting with QT so this may not be the best way to get what you want but heres what I would do.
I would create my own custom input dialog which inherits QInputDialog. I would then override the setLabelText function to check if the string length is less than 100.
If it is less than 100 then you can go ahead and display it. If not then you can choose where to add yours dots and remove words in order to bring the size down.
Once its equal to 100 characters or less, you can display it.
I will try and write an example when I get home if you would like.

Related

Qt window resize height to fit QLabel text

I want to create a window which height should be equal to the height of the child QLabel, the QLabel can be set to any size text and setWrap is True. Here is my current code:
class TextWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedWidth(230)
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QHBoxLayout(self.centralwidget)
self.horizontalLayout.setSizeConstraint(QLayout.SizeConstraint.SetMinimumSize)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.label = QLabel(self.centralwidget)
self.label.setWordWrap(True)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.setCentralWidget(self.centralwidget)
self.label.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur non urna nisl. Integer venenatis aliquet faucibus. Nam tristique massa a vestibulum congue. Vivamus nisi felis, volutpat vitae neque quis, pharetra tristique massa. Duis tincidunt et nulla a hendrerit. Vestibulum in molestie lectus.")
Actual behavior:
The text is cut off if there is a lot of it and if there is not enough of it, then there are huge margins between the edge of the window and the text, I want the window height to wrap the text, that is, the height of the window needs to be equal to the size of the text. How can this be done?
This is explained in the Layout Issues section of the layout documentation:
The use of rich text in a label widget can introduce some problems to the layout of its parent widget. Problems occur due to the way rich text is handled by Qt's layout managers when the label is word wrapped".
Note that, as a rule of thumb, you shall never rely on the size hint of a label that uses word-wrapped text. This is related to the many problems text laying out has, like unexpected font behavior, system font scaling, high DPI settings. In reality, it's a good thing that the default behavior doesn't consider the possible size hint of a word-wrapped label, otherwise there could be serious performance issues, especially while resizing.
Truth is, word-wrapped text should always be displayed in a scroll area (using a QTextEdit or with a QLabel that is placed inside a QScrollArea); the default API cannot know the infinite possibilities in which some text could be shown, and should always aim for the best result with optimal performance.
The problem is caused by the fact that there's no way to know the "best" size hint of a label that can wrap its contents, and layout managers should always try to be as fast as possible in their response, otherwise you'd risk recursion or unnecessary overhead, even for a simple label.
IF you are completely sure about the fixed width of the label, you should explicitly set it:
self.label.setFixedWidth(230)
If the width cannot be known beforehand, due to the presence of other widgets in the layout that might change the available width for the label, then you can rely on the QLabel heightForWidth(), set a minimum height for it based on the current width, and finally make a delayed call to the adjustSize() of the main window (the delay is required to allow the whole layout management to update the size hints).
from random import randrange
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
def randomText():
return ' '.join(['Lorem ipsum'] * randrange(10, 50)) + '\n\nThe end.'
class TextWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedWidth(230)
central = QWidget()
layout = QGridLayout(central)
layout.addWidget(QToolButton())
self.label = QLabel(randomText())
self.label.setWordWrap(True)
layout.addWidget(self.label, 0, 1)
layout.addWidget(QPushButton('Hello'), 1, 0, 1, 2)
self.setCentralWidget(central)
def setMessage(self, message=''):
self.label.setText(message or randomText())
self.updateSize()
def updateSize(self):
self.centralWidget().layout().activate()
self.label.setMinimumHeight(0)
self.label.setMinimumHeight(
self.label.heightForWidth(self.label.width()))
QTimer.singleShot(0, self.adjustSize)
def resizeEvent(self, event):
super().resizeEvent(event)
self.updateSize()
app = QApplication([])
w = TextWindow()
QTimer.singleShot(1000, w.setMessage)
w.show()
app.exec()
Get the size hint of the QLabel using the sizeHint() method and then use the result when you resize your window.
For example:
text = "Some very long text that will possible need to be wrapped and take up more than one line."
value = 3 # <--- raise or lower value to see adjustments
class Window(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.central = QWidget()
self.layout = QVBoxLayout(self.central)
self.setCentralWidget(self.central)
self.label = QLabel(text=text * value)
self.layout.addWidget(self.label)
self.label.setWordWrap(True)
self.resize(self.label.sizeHint())

Conditional rendering in streamlit

I have a form where I need to use some conditional rendering. Basically, the form needs to change dynamically based on what the user input is. For instance, if I ask "Where did you hear about us?" and give the users some default options (e.g. "Linkedin", "Our website"..), I want that if the user selects "Other" a st.text_input appears where the user can type the answer to the question.
The problem I am facing is that:
If I use st.form (with the st.submit_form_button), what happens is that the form does not dynamically adapt to the user's input. So the text_field won't show up at all when the user ticks "Other" in the example above.
If I do not use st.form, then the form reloads every time the user clicks on any widget. This does not affect the functionality of the form, but it does make for a very bad user experience!
Any tips on how I could either include conditional rendering within st.form or just avoid the bad user experience of the form being reloaded every time the user clicks on any widget?
Any help would be appreciated!
Instead of using form, you can create the form manually and create several containers to separate the code.
import streamlit as st
########################################################
# Sidebar section
########################################################
sb = st.sidebar # defining the sidebar
sb.markdown("🛰️ **Navigation**")
page_names = ["🏠 Home", "⚙️ Other"]
page = sb.radio("", page_names, index=0)
if page == "🏠 Home":
st.subheader("Example home")
st.subheader("What is Lorem Ipsum? ?")
lorem_ipsum = "Lorem Ipsum is simply dummy text of the printing and typesetting industry"\
"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book"
st.markdown(lorem_ipsum, unsafe_allow_html=True)
else:
other_title = '<h3 style="margin-bottom:0; padding: 0.5rem 0px 1rem;">⚙️ Other</h3>'
st.markdown(other_title, unsafe_allow_html=True)
lorem_ipsum = "Lorem Ipsum is simply dummy text of the printing and typesetting industry"\
"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book"
st.markdown(lorem_ipsum, unsafe_allow_html=True)
container_selection = st.container()
col1_cs, col2_cs = container_selection.columns([1, 2])
with col1_cs:
slider_val = st.slider("Form slider")
see_text = st.checkbox("See text")
if see_text:
st.warning("**See text** will take more time. Are you sure ?")
other = st.checkbox("Other")
if other:
st.info("Other checkbox")
result = st.button(label="other buttom")
with col2_cs:
st.caption(" ")
if result:
ccp = st.container()
with ccp:
information_title = '<h3 style="margin-bottom:0; padding: 0.5rem 0px 1rem;">📋 Ipsum is simply dummy text </h3>'
st.markdown(information_title, unsafe_allow_html=True)

NSAttributedString: Is it more expensive to redeclare attributes?

Given this string
Lorem Ipsum dolor sit amet
And given I want it to be styled like this
underlined: 0 - 26 (Lorem Ipsum dolor sit amet)
bold: 6 - 21 (Ipsum dolor sit)
red color: 12 - 17 (dolor)
Does it matter performance wise if this is declared like this
0-6 (Lorem )
underlined
6-12 (Ipsum )
underlined, bold
12-17 (dolor)
underlined, bold, red color
17-21 ( sit)
underlined, bold
21-26 ( amet)
underlined
VS if it is declared like this
0-26 (Lorem Ipsum dolor sit)
underlined
6-21 (Ipsum dolor sit)
bold
12-17 (dolor)
red color
??
This is a very simplified example of my much more complex attributed string.
I wonder if this matters performance wise either when rendering or when building this string.

applying formatting to a character range in textflows in Flex 4.10 SDK

When using any version of Flex 4.10 SDK the following code apply's the format to an entire paragraph instead of a specific character range.
https://issues.apache.org/jira/browse/FLEX-33791
<?xml version="1.0"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" creationComplete="OnCreationComplete(event)">
<s:TextArea width="100%" height="100%" id="txt" editable="true">
<s:content>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.<s:br/>
Vivamus eu erat ac est ullamcorper egestas eget nec mauris.<s:br/>
</s:content>
</s:TextArea>
<fx:Script><![CDATA[
import flashx.textLayout.edit.EditManager;
import flashx.textLayout.formats.TextLayoutFormat;
import mx.events.FlexEvent;
private function OnCreationComplete(event:FlexEvent):void
{
var objFormat:TextLayoutFormat = new TextLayoutFormat();
objFormat.backgroundColor = 0xB9CCFF;
txt.selectRange(5, 8);
var objManager:EditManager = txt.textFlow.interactionManager as EditManager;
objManager.applyFormat(objFormat, objFormat, objFormat);
}
]]></fx:Script>
</s:Application>
The three parameters for applyFormat are for three different ways the format can be applied.
The first parameter, "leafFormat" will get applied to LeafElement objects like SpanElement (or nodes, if you prefer to think of the XML that TLF generates) and will actually create a new leaf if the current (or supplied) SelectionState doesn't encompass an entire LeafElement.
The second parameter, "paragraphFormat" will get applied to the entire paragraph that the current (or supplied) SelectionState is a part of. So if I select only a few characters from a paragraph and then call applyFormat, passing in a background color for the "paragraphFormat" parameter, the entire paragraph will get the background color.
The third parameter, "containerFormat" I've never used and haven't really looked into at all. I would guess that it applies the format to the entire ContainerController object that helps lay out the text.
You can safely pass null (or completely different formats) in for any of the four parameters.
So, in short, I think to fix your problem you just change you function call to:
objManager.applyFormat(objFormat, null, null);

QCheckBox word-wrap

Is there a way to wrap text in QCheckBox like it is done with QLabel?
label = QLabel( QString.fromUtf8('long text in here'))
label.setWordWrap(True)
I tried \n which will add a linebreak but this is not dynamic if I resize the window.
It seems there is a feature request for this at https://bugreports.qt.io/browse/QTBUG-5370.
The issue is not closed, so likely this feature is not implemented. This means that it is not currently possible to add word wrap to QCheckBox.
You can try various workarounds, such as having an empty-text QCheckBox and a QLabel to the right, or try putting a shorter text for the checkbox, with a label below it with the long explanation.
You can develop a Custom widgets for QtDesigner to use this feature graphically (or not).
CheckBoxWordWrap (dynamic when resize):
In QtDesigner:
You can also use the class and modify it if the behavior is not exactly what you want.
"This is my double \n line checkbox". Now you have double line checkbox
There unfortunately is no short and simple solution for this. We have to implement this on our own.
The complete implementation of a LineWrappedRadioButton class is already provided in this related answer. You can easily covert this code into a LineWrappedCheckBox class by simply deriving from QCheckBox instead of from QRadioButton there.
Use it like this:
int main(int argc, char **argv) {
QApplication app(argc, argv);
LineWrappedCheckBox checkBox("Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua.");
checkBox.show();
return app.exec();
}
This will produce the following result:

Resources