I have a QtQuick/QML 5.6 project where I need to load 45 .ttf files representing weight variations of different (related) font families.
For example, here is a subset of the font files (three weights for two families):
EncodeSans-Thin.ttf
EncodeSans-Regular.ttf
EncodeSans-Bold.ttf
EncodeSansNarrow-Thin.ttf
EncodeSansNarrow-Regular.ttf
EncodeSansNarrow-Bold.ttf
I have added all 45 .ttf files to a .qrc in my project, but when I try to use the font family, it does not work:
Text { text:"So Thin"; font.family:"Encode Sans"; font.weight:Font.Thin }
Text { text:"Fatty"; font.family:"Encode Sans"; font.weight:Font.Bold }
If I add a single font loader for one font in each family, however, it works, for all weight variations of that font
FontLoader { source:"qrc:/fonts/EncodeSans-Regular.ttf" }
FontLoader { source:"qrc:/fonts/EncodeSansNarrow-Regular.ttf" }
Text { text:"So Thin"; font.family:"Encode Sans"; font.weight:Font.Thin }
Text { text:"Fatty"; font.family:"Encode Sans"; font.weight:Font.Bold }
I am surprised by this. It certainly appears to be using EncodeSans-Thin.ttf for the thin weight and EncodeSans-Bold.ttf for the bold weight, despite never mentioning those files in any FontLoader.
Edit: the above code does NOT work. Due to a separate bug I now know that Font.Thin was never working (was showing the Regular weight), and it's possible that bold was being simulated by the text renderer.
Am I supposed to add 45 FontLoader to my project, one for each TTF? Or is there a way to get all the TTF to be loaded with no need for FontLoader?
Repeater {
id: repeater
property var fontList: [] // e.g. Qt.resolvedUrl("qrc:///fonts/EncodeSans-Regular.ttf"), or load a list from resource/config files
model: ListModel {
id: listModel
}
FontLoader {
source: model.source
}
Component.onCompleted: {
for (var i = 0; i < fontList.length; i++) {
listModel.append({ source: fontList[i] })
}
}
}
edit: Given a list of strings and URLs you can use a repeater to load many fonts. Component.onCompleted: the script reads the list of URLS to load fonts from, and adds all of them to the list. Since the repeater model is a ListModel, the repeater will create new items when added to ListModel. Repositioning is also available to repeaters this way, but not used here.
Note: Loading the list of URLs is not given in this snippet.
Related
I have a QML app that's using a font family that has 5 weights—Light/Regular/Medium/Bold/Black—and 3 styles: Normal, Italic, and Condensed.
When I load both a 'normal' and 'condensed' style of the same weight they share the same family name; whichever style was loaded first is what is used:
FontLoader { source:"qrc:/fonts/DINPro-CondRegular.otf"; id:cond }
FontLoader { source:"qrc:/fonts/DINPro-Regular.otf"; id:norm }
Timer { running:true; onTriggered:console.log(id:norm.name==cond.name) } // outputs `true`
// This ends up using the condensed flavor
Text { text:'hi mom'; font { family:'DINPro' } }
Is there some way to tell a Text object to use a specific font file or FontLoader instance? There's an italic property for italic style, but no property for the 'condensed' flavor.
How can I use both normal and condensed styles of the font in the same document, and specify which to use for different Text?
I've found that for this particular font I can use the styleName property to control the various flavors. I just kept trying various style strings until I found ones that worked.
FontLoader { source:"qrc:/fonts/DINPro-Regular.otf" }
FontLoader { source:"qrc:/fonts/DINPro-CondRegular.otf" }
FontLoader { source:"qrc:/fonts/DINPro-CondMedium.otf" }
Text { text:'norm'; font { family:'DINPro'; styleName:'Regular' } }
Text { text:'bold'; font { family:'DINPro'; weight:Font.Bold; styleName:'Regular' } }
Text { text:'blak'; font { family:'DINPro'; weight:Font.Black; styleName:'Regular' } }
Text { text:'cond norm'; font { family:'DINPro'; styleName:'CondRegular' } }
Text { text:'cond bold'; font { family:'DINPro'; styleName:'CondBold' } }
Text { text:'cond blak'; font { family:'DINPro'; styleName:'CondBlack' } }
It feels like it's held together with tape and string, but it's working. If someone has a more robust way to handle this—especially to know exactly what strings will work for the styleName—I'll happily accept that answer instead of this one.
If I want to embed an image with smoothing I might do something like this:
package
{
public class EmbeddedImages
{
[Embed(source="/assets/image1.png", smoothing="true")]
public static const Image1:Class;
}
}
However, if I have a bunch of buttons with different icons, I want to control which icon to display using CSS, like this:
#namespace s "library://ns.adobe.com/flex/spark";
s|Button.image1
{
icon: Embed('/assets/image1.png');
}
I want the icon to be smooth. So what is the syntax for adding smoothing when embedding with CSS?
I don't have a project to test on, but see the smoothingQuality style of Image. This obviously won't work if the button uses BitmapImage to display the icon since the style is only available for Image. Odds are, it does use BitmapImage, though.
s|Button.image1
{
icon: Embed('/assets/image1.png');
smoothingQuality: "high";
}
Again, I have no way to test this so that is a complete shot in the dark. Worth a try, though
Since it's a mobile project, then the Button icon is a BitmapImage and you could try setting its members
smooth = true;
smoothingQuality = BitmapSmoothingQuality.BEST;
or maybe do that via CSS:
s|ButtonImage {
smoothingQuality: "best";
}
Is there any possibility of giving variable name to hex/rgb numbers in .qss file . For eh
myColor = #FFCC08
QPushButton { background-color: myColor;}
So that i can define the variable at the top of the stylesheet and use the variable name whereever required instead of using the hex code. Also if i need to change the color then i have to change in one place and it will be reflected throught the file.
I also searched for Saas but don't know how it can be used in qt.
Thanks :)
You could build your own tiny Sass quite easily:
1.Create a text file with definitions of variables. Use simple format like this:
#myColor = #FFDDEE
#myColor2 = #112233
#myWidth = 20px
2.In qss file use variable names:
QPushButton {
background-color: #myColor;
min-width: #myWidth;
}
3.Open both files and for each variable in definition file change its occurrence in qss file with the value (string) from the definition file. It is a simple string replacement.
4.Apply the preprocessed qss in the app.
This is the simplest solution. You can change both definition file and qss file outside the app and apply it without recompilation of code.
What you're trying to accomplish simply isn't possible using pure Qt style sheets.
You can achieve a similar effect by modifying and reloading your style sheets from within your C++ code, for example:
QString myColor = "#FFCC08";
QString styleSheet = "QPushButton { background-color: %1;}";
...
myWidget->setStyleSheet( styleSheet.arg(myColor) );
Unfortunately this has several drawbacks (inability to preview in designer, changing code rather than a style sheet), but it's about as close as you can get to what you're trying to achieve with Qt.
Another way to accomplish this would be to use Dynamic Properties. This would let you easily assign multiple properties to an object or group of objects, sort of like assigning a css class to an object.
https://wiki.qt.io/Dynamic_Properties_and_Stylesheets
For example, in your UI file, you could add a string dynamic property "colorStyle" with a value of "myStyle1".
Your stylesheet would look like:
QPushButton[colorStyle='myStyle1'] {
background-color: #FFCC08;
... any other style changes...
}
Any QPushButton you assign 'myStyle1' will follow the stylesheet if you set it globally.
Here is a solution using sass. First, install the python bindings:
pip install sass
Then, use it:
import sys
import sass
app = QApplication(sys.argv)
# Create your sass style sheet (you can also write this in a file and load the file)
style = '''
$bg-dark: #292929;
QPushButton {
color: red;
background-color: $bg-dark;
}
'''.encode('utf-8')
# Compile Sass to CSS
style = sass.compile_string(style).decode()
# And set it to your app
app.setStyleSheet(style)
I have similar, but different problem. In my case, I want to connect window size to QCheckBoxIndicator. Code below won't work due to css already use the {}.
self.checkBoxYes.setStyleSheet('''
QCheckBox::indicator {
width: {sz} px;
height: {sz} px;
}
'''.format(sz=rel_sz))
However, workaround can be achieved using old-formatted string below:
def resizeEvent(self, a0) -> None:
rel_wdth = self.width() // 20
rel_hgh = self.height() // 10
rel_sz = str(min(rel_hgh, rel_wdth))
self.checkBoxYes.setStyleSheet('''
QCheckBox::indicator {
width: %s px;
height: %s px;
}
''' %(rel_sz, rel_sz))
return super().resizeEvent(a0)
I've got a StyleableTextField that displays very basic HTML. To format the HTML I currently use a Stylesheet declared in AS3.
This works fine, but is rather inefficient for the designers to edit colors and stuff, so I need to include these tags in my main CSS.
The AS3 CSS declaration looks like this;
_styleSheet = new StyleSheet();
_styleSheet.setStyle("p", {fontSize:'15',color:'#FFFFFF', fontFamily: 'Courier New', fontWeight:'bold'});
This gets assigned to the StyleableTextField using the usual styleSheet = _styleSheet way.
The main CSS file is declared in my main application like this: <fx:Style source="Main.css"/>.
I already have CSS tags for spark components in my CSS, such like the following;
s|TextInput
{
contentBackgroundAlpha: .5;
contentBackgroundColor: #202020;
focusColor: #e1333a;
}
However, I need to address the very instance of StyleableTextfield in the CSS (I've got other's in my app, but only this one displays HTML text).
Has anyone got an idea how to do this?
Working on a mobile project btw.
Flex supports a CSS id selector.
#instanceID
{
...
}
or
ObjectType#instanceID
{
...
}
I haven't been able to test this thoroughly, but it appeared to work for me:
#_objectName
{
p: pstyle;
}
.pstyle
{
fontSize: 15;
...
}
I want to change the font characteristics for buttons in the toolbar of the RichTextEditor, but I want them to be different than other buttons in my application. Is there any way to do this with just CSS? I know that I can do it with setStyle if necessary...
One way to do it, since the RichTextEditor's sub-components are declared in MXML and are therefore publicly accessible, is to assign their styleName properties individually at runtime (after the container's creationComplete event fires, to be sure the editor and all its children have been created), like so:
<mx:Style>
.myRTECombo
{
color: #FF0000;
}
</mx:Style>
<mx:Script>
<![CDATA[
private function creationCompleteHandler(event:Event):void
{
rte.fontFamilyCombo.styleName = "myRTECombo";
rte.fontSizeCombo.styleName = "myRTECombo";
}
]]>
</mx:Script>
<mx:RichTextEditor id="rte" />
The Flex docs don't call out the subcomponents ("boldButton", "fontSizeCombo", et al) by ID, but the component's source is available for viewing, so you should be able to get all the info you need from the source code itself. Since I use FlexBuilder, I usually use the Eclipse Ctrl+click shortcut, on the tag/class name, to jump into the associated class-definition file, but you can also open the source file directly at [installDir]/sdks/[version]/frameworks/src/mx/RichTextEditor.mxml to have a look for yourself.
I'm sure there are other approaches (setStyle being one, although its explicit use is generally discouraged for performance reasons), but this ought to work out for you. One thing to note, though, as you'll see when you dig into the component's source, is that many of the buttons in the default button set actually use PNGs (e.g., icon_style_bold.png), not text, which is why my example includes a reference to the ComboBox instead, so you can see how the color changes apply; if you want to change the look of the buttons, be aware they're using the styleable icon property, not font-style settings, for their look and feel.
Hope it helps!
Thanks #Christian Nunciato! This is my final code, in my component that is a RichTextEditor (extends it). In the creationComplete, I call this
private function setUpStyleNames():void {
setUpStyleNamesInner(toolbar.getChildren());
setUpStyleNamesInner(toolBar2.getChildren());
}
private function setUpStyleNamesInner(children:Array):void {
for each (var child:DisplayObject in children) {
if (child is UIComponent) {
UIComponent(child).styleName = "rteInnards";
}
}
}
and then in my styleSheet, I have this
.rteInnards {
color: #FF0000;
fontSize: 25px;
}
Awesome. Thanks again!