Qt stylesheet to use an image from memory - c++

Qt stylesheets allow customizing of icons, for example the drop-down icon in a combo box. But all examples and docs which I have yet seen require having the image stored in a url. Then you can write for example QComboBox::down-arrow { image: url(path-to-file.png); }.
My question is: isn't there any trick which would allow to work around the fact that the file must be stored somewhere and use for example a pixmap from the memory?
I am asking because recently I found a nice hack which allows using QPixmap data to be used when displaying images in widgets which otherwise accept richtext (HTML formatted). See this code:
QPixmap preview;
// ... generate the pixmap here
QByteArray data;
QBuffer buffer(&data);
preview.save(&buffer, "PNG");
QString img = QStringLiteral("<img src='data:image/png;base64, %1'/>").arg(QString::fromLatin1(data.toBase64()));
//... and now you can display the image anywhere Qt accepts HTML formatted text,
// e.g. in QToolTip (which is my usecase).
This way I can use data from memory without saving it to file.
I am curious if there isn't any similar trick for images used in Qt style sheets.

There's nothing special, just put path to your image:
setStyleSheet("background-image: url(/path/to/file.png);");

Related

How to load multiple font of same familiy

I am writing an application using the Qt framework. In the display, I have to show multiple information, but using different types of font of the same family, Montserrat.
What I have done so far to load the fonts is:
int ultralightid = QFontDatabase::addApplicationFont(":/Montserrat_UltraLight.tff");
QString UltraFont= QFontDatabase::applicationFontFamilies(ultralightid ).at(0);
QFont font1(UltraFont,QFont::Normal);
font1.setPixelSize(50);
int lightid = QFontDatabase::addApplicationFont(":/Montserrat_Light.tff");
QString LightFont= QFontDatabase::applicationFontFamilies(lightid).at(0);
QFont font2(LightFont,QFont::Normal);
font2.setPixelSize(150);
label1->setFont(font1);
label2->setFont(font2);
label1->setText("bla bla");
label2->setText("bla bla");
The font sizes are correct, but the font itself it is not. From what I have noticed (trying with Hairline_Montserrat,Light_Montserrat,UltraLight_Montserrat), it is as if the fonts have a sort of priority. If I declare them all, all the fonts are the Light one, if I comment that font type, all of them are Hairline one, otherwise (last priority) the labels use the ultralight font.
I have tried adding other font type (from other families) and in that case my code works correctly.
If I use
qDebug()<<QFontDatabase::applicationFontFamilies(ultralightid);
qDebug()<<QFontDatabase::applicationFontFamilies(lightid);
both of them print the family "Montserrat".
I use the qrc file and the AUTORCC flag in the CMAKE (it should be similar using qmake) and all the file are uploaded correctly.
Do you know if there is another way to add fonts of the same family? Or is there something I am doing wrong?
Here are the fonts:
https://www.onlinewebfonts.com/download/9d31c906a6cc6064bbe7d33d51058317 light
https://it.allfont.net/download/montserrat-light/ ultralight
This is an old question but I was just struggling with exactly the same problem when trying to load normal, bold, ... versions of a font family in Qt.
I solved the problem (although in a somewhat hacky way) by simply giving each of the ttf files a different family name. I used Typograf, simply open the font, right click to open properties and then click rename. There are probably many other tools that do this too.
You don't need to manage font files from one family separatelly.
I suggest this solution:
Create a folder with all ttf's of the same family.
Load all files from the folder via id = QFontDatabase.addApplicationFont(path)
Collect all font families from these files via QFontDatabase.applicationFontFamilies(id)
Check if only one and desired family is loaded, and the family name is exactly the same as requested, or warn the user about these errors.
Create font object font = QFont(family)
Then for example, font.setItalic(True). If Italic version of family is loaded, it will be used, otherwise it will be created from Regular by QT.

QT QIcon properties for custom widget in designer

I have been working for a little while now on creating a QT custom designer widget for GUI menus. The idea being that you simply drag it into the designer, select the number of frames you'd like, how many buttons per frame, etc. and it generates and sizes everything for you.
The way the widget is structured there are properties to configure each button for the frame you are in. For example, you would use the button0Text field to enter text under Button0 while editing in frame 0, then use it again to edit Button0 which is in frame 1. Both buttons would retain the individual changes for each frame.
The Problem
Normally when I switch frames all of my properties are updated to reflect the status of the frame. The exception being QIcon. The correct icon is retained in the actual graphical representation and builds correctly, however the file path in the property list is always of the last edited for that property. I think this will be extremely confusing to an end user and I have found no way to fix it. So for example, if I set text and icons in frame 0 then switch to frame 1 the text in the property list will update to reflect the state of frame 1 but the icon path names will still show my last edit in frame 0 and not the actual icon in frame 1.
I have tried things as simple as:
setProperty("button0Icon", getButton0Icon());
That code works on properties like text, but not for the icon. I try executing it immediately after changing frames.
I have also tried:
#ifndef Q_WS_QWS
QDesignerFormWindowInterface *form = QDesignerFormWindowInterface::findFormWindow(this);
if(form){
QDesignerFormEditorInterface *editor = form->core();
QExtensionManager *manager = editor->extensionManager();
QDesignerPropertySheetExtension *sheet;
sheet = qt_extension<QDesignerPropertySheetExtension*>(manager, this);
int propertyIndex = sheet->indexOf("button0Icon");
sheet->setChanged(propertyIndex, true);
sheet->setProperty(propertyIndex, getButton0Icon());
}
#endif
And:
int propertyIndex = this->metaObject()->indexOfProperty("button0Icon");
QMetaProperty property = this->metaObject()->property(propertyIndex);
property.write(this, QIcon());
Nothing seems to update the property list in the designer.
I have all properties, including all QIcon properties properly declared in the header file with Q_PROPERTY and assigned getter and setter functions.
To be clear, the icon values are indeed retained through each frame when compiled. So it is functioning, just unclear for most users.
If anyone has any experience with this or any ideas please let me know. Thanks.
I have discovered that QIcon does not store file names/paths. The file names are only used for the creation of the QIcon. I think this is most likely the reason I do not get any feedback in the Property Browser for my QIcon properties.
Instead I have chosen to hide this property in the designer and add three new ones. Three QUrl properties, each of which is used to supply an image file. I use three because I want to construct a QIcon that contains Modes/States for normal, disabled, and pressed operations.
I take each of these QUrls and save them in QStringLists behind the scenes so their values are stored. I then construct my QIcon using the file names provided from the QUrls.
I would much prefer to be using the native QIcon in the designer for this, any thoughts or feedback are appreciated.

QTextEdit change font of individual paragraph/block

Using a QTextEdit, I need to change the font attributes of each paragraph individually. This is similar to how many word processors change the font of a paragraph when the user select a style from a menu (not a specific formatting).
Ideally, I would like to apply a QTextCharFormat (or equivalent) to a block (paragraph) just before it is laid out and rendered, but I would prefer that no font attribute be actually inserted in the text, as I don't want this information in the file but I need to preserve any bold/italic/underline attributes that the user might have set to words within paragraphs (I intend to save the needed information in a QTextBlock::userData). However, I can't figure where I would need to insert a function to perform this task.
I figured I could not change the QTextCharFormat of a paragraph from either QTextBlock nor QTextCursor as this only applies to new blocks, it doesn't affect blocks with existing text.
I checked out QTextLayout but I don't think my answer is there.
I have been looking for a solution to this problem for a few days now. I would be really gracious for any pointer in the right direction.
I have years of experience with C++, but I'm somewhat new to Qt. Using Qt 4.8.
Edit:
I added emphasize (bold) above to an important part of what I'm trying to do. In other word, what I'd really like to do is be able to apply the font attributes to the block of text (perhaps a temporary copy) just before it is displayed. I'm totally comfortable with deriving and modifying (even reimplement) any class that I need to in order to achieve that goal, but I need to be pointed to the right direction as to what I actually need to change. As a last resort, I could also modify some Qt class directly if that is necessary for the task, but again would need to know what class I need to touch. I hope this is clearer. I find it difficult to explain this without being allowed to tell you what the application will do exactly.
[Required Libraries]
#include <QTextEdit> // not needed if using the designer
#include <QTextDocument>
#include <QTextBlock>
#include <QTextCursor>
[Strategy]
QTextDocument
I need it to manage the blocks. The function QTextDocument::findBlockByNumber is quite handy to locate the previous blocks, and I think it is what you are after.
QTextBlock
Container for block texts. A nice and handy class.
QTextCursor
Surprisingly, there is no format-setter in QTextBlock class. Therefore I use QTextCursor as a workaround since there are four format-setters in this class.
[Code for formatting]
// For block management
QTextDocument *doc = new QTextDocument(this);
ui->textEdit->setDocument(doc); // from QTextEdit created by the Designer
//-------------------------------------------------
// Locate the 1st block
QTextBlock block = doc->findBlockByNumber(0);
// Initiate a copy of cursor on the block
// Notice: it won't change any cursor behavior of the text editor, since it
// just another copy of cursor, and it's "invisible" from the editor.
QTextCursor cursor(block);
// Set background color
QTextBlockFormat blockFormat = cursor.blockFormat();
blockFormat.setBackground(QColor(Qt::yellow));
cursor.setBlockFormat(blockFormat);
// Set font
for (QTextBlock::iterator it = cursor.block().begin(); !(it.atEnd()); ++it)
{
QTextCharFormat charFormat = it.fragment().charFormat();
charFormat.setFont(QFont("Times", 15, QFont::Bold));
QTextCursor tempCursor = cursor;
tempCursor.setPosition(it.fragment().position());
tempCursor.setPosition(it.fragment().position() + it.fragment().length(), QTextCursor::KeepAnchor);
tempCursor.setCharFormat(charFormat);
}
Reference:
How to change current line format in QTextEdit without selection?
[DEMO]
Building Environment: Qt 4.8 + MSVC2010 compiler + Windows 7 32 bit
The demo is just for showing the concept of setting the format on a specific block.
Plain text input
Format 1 (notice that it won't bother the current cursor in view)
Format 2
You can use QTextCursor to modify existing blocks.
Just get a cursor and move it to the beginning of the block. Then move it with anchor to create a selection.
Set this cursor to be the current cursor for the text edit and apply your changes.
QTextEdit accepts HTML so all you have to do is to format your paragraphs as HTML. See example below:
QString text = "<p><b>Paragraph 1</b></p><p><i>Paragraph 2</i></p>";
QTextCursor cursor = ui->textEdit->textCursor();
cursor.insertHtml(text);
That will create something like this:
Paragraph 1
Paragraph 2
Having said that, there is only a subset of HTML that is supported in Qt. See Supported HTML Subset

Custom text (code) areas in QTextEdit

I am interested in creating a text object type (inheriting QTextObjectInterface) that behaves like a code area:
distinctive background
border
fixed-width font
editable content
the instances need to be identifiable to code, so that content inside them may be extracted (separate code from surrounding content)
saving / loading (from regular html files)
syntax highlighting would be a plus, but is not really required
The other areas of the document would need to behave the usual way (font properties editable, colors editable, etc).
Qt provides an example for implementing custom text objects with QTextEdit. This looks like the hard way, since new text object can't make use of the existing infrastructure inside QTextEdit / QTextDocument.
QTextObject is
a base class for different kinds of objects that can group parts of a QTextDocument together
so inheriting it may be a choice, but neither its source files in Qt SDK package nor Google searches revealed helpful information.
QTextFrame inherits QTextObject so, again, it may be a feasible base class if some hints about this path are to be found.
In an simple HTML file all this (except syntax highlighting) would be easy. QTextEdit takes html as input and is able to export html, but the structure is lost in the process.
<code class="code-sample">
int i = 0;
</code>
QWebView is read-only, by the way. It advertises that:
Parts of HTML documents can be editable for example through the contenteditable attribute on HTML elements.
There may be other platforms where this is readily available, but the text editor needs to be used inside Qt Creator as a plug-in, so using Qt framework makes sense.
Bottom line: how does one implement code areas in a QTextEdit widget?
Later edits:
using Qt sdk from trunk (identifies itself as 4.8.4)
Qt Creator from trunk (Qt Creator 2.6.81)
I have found out that implementing this is possible using QTextEdit / QTextDocument.The most simple implementation that I can think of is presented in this answer for the reference of future seeker.
Notice that saving/loading needs to be customised as regular .toHtml() will not preserve the information needed.
Inserting a code block is simple:
QTextFrame * frame;
frame = cursor.insertFrame( code_block_format_ );
connect( frame, SIGNAL( destroyed() ),
this, SLOT( codeBlockDeleted() ) );
code_blocks_.append( frame );
notice the two variables that you can save in the class:
QTextFrameFormat code_block_format_;
QList<const QTextFrame*> code_blocks_;
We need the format for frame to be consistent and distinctive. It mat be initialised in constructor to something like:
code_block_format_.setBackground( QBrush( Qt::yellow ) );
code_block_format_.setBorder( 1 );
code_block_format_.setBorderStyle( QTextFrameFormat::BorderStyle_Inset);
code_block_format_.setMargin( 10 );
code_block_format_.setPadding( 4 );
We need the list so we can tell if a certain frame is a code box or not. Since all objects inheriting QTextObject need to be created by QTextDocument::createObject() we can't simply subclass the QTextFrame (actually I think we can, but not sure yet).
Now separating the code content from the rest may be done the usual way:
for ( it = frame->begin(); !(it.atEnd()); ++it ) {
child_frame = it.currentFrame();
child_block = it.currentBlock();
if ( child_frame != NULL )
{
if ( code_blocks_.contains( frame ) )
{
/* ... */
}
}
} /* for ( it = frame->begin(); !(it.atEnd()); ++it ) */
but notice that this is over-simplified for the sake of brevity. One needs to take into account nested frames.
If you are interested in a full implementation check out the git repository (work in progress, November 2012).

Qt: How can I access the actual widgets on a page in WebKit?

Is there a way to access the widgets generated by INPUT and SELECT on a page in WebKit, using Qt?
On a related note, does WebKit provide these widgets, or does it delegate back to Qt to generate them?
There are no "widgets". Newer browsers render all elements themselves to allow overlays etc.
If you want to manipulate them use the DOM.
Everything inside in QWebView does not use the conventional Qt widget system. It's only HTML, rendered by WebKit. But you can access to html by using the evalJS function. Example of code:
QString Widget::evalJS(const QString &js)
{
QWebFrame *frame = ui->webView->page()->mainFrame();
return frame->evaluateJavaScript(js).toString();
}
evalJS(QString("document.forms[\"f\"].text.value = \"%1\";").arg(fromText));
evalJS(QString("document.forms[\"f\"].langSelect.value = \"%1\";").arg(langText));
evalJS(QString("translate()"));
QString from = evalJS("document.forms[\"f\"].text.value");
QString translation = evalJS("document.forms[\"f\"].translation.value");
ui->textEditTo->setText(translation);