I am using styles for first time and get strange behavior.
The font properties etc inherit fine but my text value is replaced with the text value from the referenced TLabel.
Am I doing something wrong?
km = new TLabel(Bord);
km->Parent = Bord;
km->Position->X = 42;
km->Position->Y = 7;
km->Width = 38;
km->Height = 14; //up to here these properties are fine
km->StyleLookup = "style_km"; //inherit style from other TLabel
km->Text = "9009 km"; //this is ignored - the text from other TLabel displays at runtime
I'm guessing what you've done here is put a label on the form and set it's StyleName to 'style_km', then put a second label and set the StyleLookup to 'style_km' to make it look like the first label.
However, when you make a component into a style, as you are doing with the first label, the componnt(s) which use the style will inherit all the properties of the style which, here, includes the text.
Also the style for a TLabel should be a TText[1]. A TLabel knows to look for a TText and to set it's text into a TText. It doesn't know what to do if the style is a TLabel (i.e. different component and which doesn't inherit from a TText).
What you need to do is put a TText on the form, somewhere where it won't be seen, and use that as your style.
But bear in mind that putting styles on a form is not the ideal what if creating a style. It is great for learning about styles, since it's a quick way to create and play with them but the need to hide the components etc. means it's not ideal for production use.
If you're developing for desktop, right click a TLabel and select 'Edit custom style' which will copy the current style to the style designer for you to edit.
On mobile you'll need to add a TStyleBook, set the StyleBook property of the form to point to it and double click the TStyleBook to create a style from scratch.
[1]Some styles, especially on mobile need something other than a bog standard TText for text items.
Related
I have two widgets
first, a QLineEdit that has a stylesheet (assume not accessible or changeable) that sets the color of the text to some color (e.g., red).
second, QLabel that has a default text color (e.g., black)
How can I get the color of the text in the QLineEdit, and set it as the color in the QLabel
l1 = QLineEdit()
color_to_be_set= l1.palette().highlight().color().name() # this approach is giving the wrong color
q1 = QLabel()
q1.setText("the text")
# then set the new color
"Trial#1 (Not working at all, not changing the color)"
palette = q1.palette()
palette.setColor(QPalette.WindowText,QColor(color_to_be_set))
q1.setPalette.....
"Trial#2, gives the wrong color"
q1.setStyleSheet("color:{}".format(color_to_be_set))
As already explained in comments, there's no public API to access properties set by stylesheets, and I sincerely doubt there could be any (at least, with the current implementation, including Qt6).
That said, there is some level of access to those properties, but it only works for the following:
background and background-color (which are the same);
color;
selection-background-color;
selection-color;
alternate-background-color;
Whenever any of the properties above is set, the palette of the widget is altered with the following palette color roles:
QSS property
QPalette role(s)
background, background-color
Base, Button, Window, backgroundRole()*
color
Text, ButtonText, WindowText, foregroundRole()*
selection-background-color
Highlight
selection-color
HighlightedText
alternate-background-color
AlternateBase
The * values are references to the widget class definitions (for instance, QPushButton normally uses Button as foreground role). They may be overridden by their respective setter functions.
Also, those properties only support the QSS Brush types: plain colors, gradients or palette(<role>). No pixmaps here!
Remember that in order to get proper access to those properties, the widget must be polished, which means that, if the widget has not been ever shown yet, calling ensurePolished() is mandatory:
Ensures that the widget and its children have been polished by QStyle (i.e., have a proper font and palette).
This means that any new Qt widget created without any already polished parent will use the system palette.
Consider the following:
from PyQt5.QtWidgets import *
app = QApplication([])
app.setStyleSheet('* {color: green;}')
source = QWidget()
# source.ensurePolished() # leave this commented for now
color = source.palette().windowText().color()
target = QWidget(styleSheet='background: {}'.format(color.name()))
target.show()
app.exec()
Then uncomment the fifth line, and see the result.
Now, there are a few catches.
When a stylesheet is set, any widget affected by it gets it's style() overridden by a private QStyleSheetStyle. That style is not exposed by the API and completely takes control over the style set for each affected widget.
But not always.
Take this snippet:
from PyQt5.QtWidgets import *
app = QApplication([])
app.setStyleSheet('* {background-color: black;}')
topLevel = QTextEdit()
topLevel.show()
parent = QWidget()
layout = QVBoxLayout(parent)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(QTextEdit())
parent.show()
app.exec()
With my current style (oxygen), the two backgrounds are slightly different:
On the left there's the topLevel widget, on the right the parent. As you can see, the underlying style still has some level of control.
This is an important aspect that has to be kept in mind, and trying to override it with a QProxyStyle won't be enough: the QStyleSheetStyle will "take control" and completely ignore the overridden functions, except for a very few like drawItemText(). Any other function will be called on "the C++ side" implementation, for which there's no useful override in the python bindings.
Also, whenever the underlying style is still used internally by the QSS, the result is that the color properties will be used just like any QPalette: they are reference colors, not the actual ones. Any widget will use the style implementation, which might use different color roles, or completely alter the color depending on the situation.
Whenever the default style is used (even through QStyleSheetStyle modifications), the palette is just a reference, not unlike a physical palette: give the same basic color palette to two styled painters, and they will use its colors in different ways. The actual color shown to the user might be slightly or even completely different and possibly ignored.
Concluding, the following aspects are of utmost importance:
just created widgets will use the default palette;
there is no access to border properties, nor margins and paddings (with the last two also depending on the inherited style);
top level widgets might behave differently;
the style might not completely adhere to the colors set (and even ignore them);
palette colors are references: the style might use a role for an unexpected purpose, or completely ignore it; some common styles use the Button role for item view headers, other use the Window role;
while normally respected, the above color properties might be altered by the style, just like any palette;
basic QSS color properties can be properly accessed only after the widget has been polished: ensurePolished() has to be called, which normally happens after the first visibility change and any setStyleSheet() call that affects the widget (see QStyle.unpolish() and QStyle.polish());
QPalette uses QBrush for any of its roles and groups, which could be any of the following: a QColor, a QGradient or a QPixmap; this means that if a palette role uses a gradient or pixmap, the returned color() will be invalid, etc.;
background-image does not update the palette (in fact, it's not listed in the table above); the same goes for border-image (as said above, there is no access to border properties);
the fusion style is (usually) the most reliable style to be used for extended stylesheet implementation; when unsure or getting unexpected behavior, use QApplication.setStyle('fusion') or widget.setStyle(QStyleFactory.create('fusion'));
OS styles potentially override drawing with private pixmaps in order to respect the standard OS appearance;
complex widgets require full and explicit values for their properties; never set generic properties (aka, no selectors) for parent widgets or the application[1], including QComboBox, QScrollBar and all QAbstractScrollArea subclasses (including item views);
So, considering all this, as long as a standard QStyle is used and the widget is polished, the roles explained in the above table should return the colors set in the supported properties of any stylesheet, including inherited ones.
But you can never be sure about that, and you always have to be aware of it.
[1] in the code examples above I did use generic stylesheets, but that was on purpose and for simplicity; that practice is usually highly discouraged for normal usage. Always use selectors when setting stylesheets for parents and complex widgets (see above).
Color newColor = new Color(197,222,90);
JButton newButton;
newButton = new JButton(icon);
newButton.setBacgroundColor(newColor);
When it is pressed it changes color. How can I keep it from changing color? I have multiple buttons, so if there is solution in one or two rows please help me, and keep in mind that I'm beginner, writing some huge classes won't help me, because I have multiple buttons with different names to be affected with this.
EDIT: Solution in one line is:
UIManager.put("Button.select", newColor);
But it changes all button colors but I need another to have different a color.
EDIT2: After some research I figured out there isn't an easy solution (but it should be). How I see it I have 2 solutions, 1. is to break buttons to separate classes and set UIManager for them, and second is to make custom buttons. It is just too much work for button.
I've found nothing that can change that particular behavior on a normal JButton. The problem being, that whatever you write in your actionlistener for the button, will occur AFTER you've let go of the mousebutton, and not "while clicking".
There are workarounds, however.
My preferred choice is, to remove all graphics from the button, and then add your own images to the button's regular and pressed states. You could take a screenshot of your GUI, cut out the button, and set that image to be both states.
JButton myButton = new JButton();
// Sets button x, y, width, height. Make the size match the image.
myButton.setBounds(5, 30, 100, 30);
// Remove border-graphics.
myButton.setBorder(null);
// Remove default graphics from the button
myButton.setContentAreaFilled(false);
// Remove the focus-indicating dotted square when focused (optional)
myButton.setFocusPainted(false);
// Here, myImage is a simple BufferedImage object.
// You can set one like this, provided you have an "images" package,
// next to your main class (ex: com.somecompany.someprogram.images),
// that contains an image:
BufferedImage myImage = ImageIO.read(getClass().getResource("images/myImage.png"));
// Then we simply apply our image to both states for the button, and we're done.
myButton.setIcon(new ImageIcon(myImage));
myButton.setPressedIcon(new ImageIcon(myImage));
Obviously there are many ways to retain and load an image, but since that's not the issue here, I'll leave additional methods out of it.
There's no need to go through it all countless times, though. It should be pretty easy to write your own custom implementation of the JButton class, in which a custom constructor takes a single parameter, being the BufferedImage, and then the constructor sets it up accordingly (changes the icons). Then all you have to do when you create a new JButton, is to use your own class, and pass it an image:
JButton btn = new MyCustomJButton(myImage);
You could also easily get along with very few images. All you need is a HashMap which holds all the images, with a String as a key. Imagine you need 4 OK-buttons. You make a single image of a button with the text "OK" written on it. Then you put that image into the HashMap, like so:
myMap.put("OK", myImage);
Then you could do this when creating a button, over and over again if you'd like more:
JButton btn = new MyCustomJButton(myMap.get("OK"));
Alternatively:
Another way of achieving this, which is pretty elaborate, but probably considered "the right way", is to use ButtonUI, as presented in this answer to another post.
If the OP is referring to the temporary change of background colour on a button with an icon at the moment the mouse is pressed, the following statement does the trick:
button.setContentAreaFilled(false);
"If you wish to have a transparent button, such as an icon only button, for example, then you should set this to false."
This took me a long time to figure out. It seems to be a little known technique, perhaps since its name gives little clue as to its effect.
With only first lane we can still see that it is clicked. You need to combine those two:
button1.setContentAreaFilled(false);
button1.setEnabled(false);
and if you don't wanna in grey color you put another button under him.
panelname.add(button1,+5,+5); \\(first not clicable, not visible button, notice +5)
panelname.add(button2,-5,-5); \(-5,-5 means it is 5 points under panel)
the default title only contains text, just like the "Apples" title in the above image.
is that possible to add image in the title.
or
is there a way developer can build a customized TitledPane ?
thanks
Use setGraphic method
TitledPane tp = new TitledPane("hi");
tp.setGraphic(new Rectangle(10, 10));
As far as I know, you can set the graphics via the css property "-fx-graphic" as well.
See Oracle Defintion for JFX and CSS, here for elements of type Labeled.
To remove the button completely, you could either
set tp.setCollabsible(false); or
use the .titled-pane CSS class to set the property "-fx-collapsible" to false.
See Here (same side as above, but for TitledPane).
I want to know how to create a label that contains two icons, one on each side and set it as the title bar for the form element (LWUIT widgets).
Form has a function to get a titleArea then you can put some components what you want.
Form f = new Form();
Container c = f.getTitleArea();
Label iconLabel1 = new Label("leftIcon");//using Image
Label iconLabel2 = new Label("rightIcon");//using Image
c.addComponent(BorderLayout.WEST, iconLabel1);
c.addComponent(BorderLayout.EAST, iconLabel2);
You can just add a component to the north portion of the screen which is the recommended way that will work properly and won't break for newer versions of LWUIT/Codename One.
When you don't set a title it will just work and you can give it the Title UIID. LWUIT 1.5 and newer have a TitleArea container but I suggest you stay away from it since CodenameOne customizes it quite allot for iOS/Android 4.x etc.
Use the setTitleComponent(Label title) method.
EDIT :
Derive the Label class and implement the paint method where you can use the Graphics method to draw Images and texts. Also set the label's text position to Label.CENTER .
I want to change grid row color when I click a row in Wicket.
Do you have any suggestion?
Without actually seeing your code it's difficult to tell what is the more suitable way of doing this for you.
If you want to change to a specific color known at page generation time, do it client-side (javascript).
Make sure the grid row has a wicket:id so that Wicket can have control over it. Add it as a WebMarkupContainer if you haven't got it. Add a SimpleAttributeModifier for the onclick attribute that will change the css class of the element. For instance:
rowMarkupContainer = new WebMarkupContainer("row");
String javascript = "this.setAttribute('class', 'myClass');";
rowMarkupContainer.add(new SimpleAttributeModifier("onclick", javascript);
Where myClass is a CSS class that uses a new color.
Alternatively, you can always hardcode the onclick event handler in the HTML without specifying a wicket:id.