Size of QGroupBox decorations - qt

I need to calculate exact width of QGroupBox. I have the width of its child, but I struggle to calculate width of QGroupBox decorations (meaning total_size - children_size - layout_space). The group box has exactly one child in a QBoxLayout.
Currently I do it in a following way:
int width = layout()->contentsMargins().left() +
layout()->contentsMargins().right() +
6; // <--- magic number
width += child->maximumWidth();
I got the '6' from trial and error and it works on my system's style (KDE's Oxygen) but I'd like to get it in a platform independent manner.
Is there any way to obtain it?

Have you tried to use QWidget::frameSize() on the QGroupBox? This should return the full size of the widget including any decoration.

Related

Angular / CSS style change width of row items

I am conceiving a horizontal bar containing items.
They must all be of same width, having the same spacing between them.
They can expand as much as they want vertically (
stackblitz here
Problem:
How to automatically set the width of the row elements? Here I simply put a value that looks good: width:200px.
I want them to have a width dependent on the number of element per row.
What I tried:
Using elementRef in Horizontile (component holding the individual tiles, displaying with *ngFor) to get the width of this element:
currentWidth:number;
constructor(private el:ElementRef) {}
ngAfterViewInit(): void {
this.currentWidth=this.el.nativeElement.offsetWidth;}
it returns 5. (??) Using .width returns nothing. Also this is not recommended, I'd like another solution, less coupling.
I noticed I can make use of width:inherit; in the css of the individual tile component, which allows me to set the style from the horizontal list component.
<app-tile [style.width.px]="0.9*currentWidth/nDisplayedTiles" [tile]="item"></app-tile>
As the currentWidth value is zero, of course it doesn't work;
I tried setting it in % but the inherits css tag keeps the %, which is not the intended effect.
Why is the app-tile styling not cared about if inherits is not set?
I tried using ViewEncapsulation but it had no effect either.
This looks like a trivial matter though: did I just miss something?
You can use the offsetParent (link) width and create a method to return the value on each of the cells and call it in your [style.width.px], something like the following will work.
The HTMLElement.offsetParent read-only property returns a reference to the element which is the closest (nearest in the containment hierarchy) positioned ancestor element.
stackblitz
ngAfterViewInit(): void {
//added this as the compiler was throwing ExpressionChangedAfterItHasBeenCheckedError
setTimeout(() => {
this.currentWidth=this.el.nativeElement.offsetParent.clientWidth;
});
}
getWidth(): number{
let width:number = 0;
//you may need to change this value to better display the cells
let multiplier = 0.7;
width = (this.currentWidth * multiplier) / this.ndisplayTiles;
width = Math.round(width);
return width;
}
<app-tile [class]="'layout-tile'" [tile]="item" [style.width.px]="getWidth()">
</app-tile>

Set QGraphicsTextItem text contents of exact height and width

I am required to create text items with exact width and height of text contents.
The height of the text is the most important requirement.
The position of the text should be relative to the text itself.
I also have to be able to place it on canvas in an exact spot.
Assuming a (printable) canvas (on a larger QGraphicsScene), say 5 inch width and 1 inch height, my text should be able to stretch top-bottom-left-right - and be placed on canvas, not part in part out.
I am sub-classing QGraphicsTextItem for my item type. I am resizing it, using QTransform(), to required size - in inches or mm or pixels (72*in).
Also setting the document() margin to 0, and anything inside (like QTextBlockFormat margins) also to 0.
I have implemented a setItemSize(QSizeF sz) (with sz in pixels), that resizes the QGraphicsTextItem as required.
The sz is initialized using the item bounding rect.
Assuming no wrap, single line text (multi-line could be solved separately once this issue is resolved).
When adding the item to canvas, I still see a top and bottom margin - and this varies based on font choice.
I drew a rectangle around the item to see it.
The top/bottom distances depend on font choices.
I have tried to use font metrics to determine these distances (in paint() I have been drawing lines to try to determine the position and rectangle in which the text fits).
I would be happy to at least be able to determine correct size to use for upper case, no accents or special characters fonts (it would be a start, though naturally I would need to be able to use any characters).
But at least some way to determine the size and position (relative to the (0,0) of item) of the text content even in the simplest case.....
The font metrics tightBoundingRect() seems the most accurate for size, but it seems impossible to determine its position so that I can somehow create my items correctly, and maybe resize/shift them correctly to fit on canvas.
Here are some examples of my struggle to determine at least exact size and position of text, relative to the (0,0) of the item (assuming that once I do that, I am able to expose that info to outside or include the shift in the item transform on resize).
Notice that the size of the text advertised by font metrics does not always cover the text, and for different fonts I am not able to position the tight bounding rect (magenta) around the text itself. (I did multiple guesses, the code below is just one - the lines are trying to show different font metrics sizes).
The above were experiments in paint function of the text item inheriting QGraphicsTextItem:
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
// draw text
QGraphicsTextItem::paint(painter, option, widget);
QPen p;
p.setWidthF(0);
QFontMetricsF fm(this->font());
qreal ascent = fm.ascent(),
descent = fm.descent(),
hheight = fm.height();
QRectF r = QGraphicsTextItem::boundingRect();
QRectF rFont= fm.tightBoundingRect(toPlainText());
qreal xmax = r.right();
painter->save();
painter->setBrush(Qt::NoBrush);
// where is "ascent + descent"
p.setColor(Qt::green);
painter->setPen(p);
painter->drawLine(QPointF(2, ascent), QPointF(2, ascent + descent));
painter->drawLine(QPointF(2, ascent + descent), QPointF(xmax/2, ascent + descent));
// where is "height"
p.setColor(Qt::red);
painter->setPen(p);
painter->drawLine(QPointF(xmax/2, 0), QPointF(xmax/2, hheight));
painter->drawLine(QPointF(xmax/2, ascent + descent), QPointF(xmax, ascent + descent));
// where is "ascent"
p.setColor(Qt::yellow);
painter->setPen(p);
painter->drawLine(QPointF(6, 0), QPointF(6, ascent));
painter->drawLine(QPointF(6, ascent), QPointF(xmax, ascent));
// something that may look like top of the text
p.setColor(Qt::blue);
painter->setPen(p);
qreal yyy = ascent + rFont.y() + 1;
painter->drawLine(QPointF(5, yyy), QPointF(xmax, yyy));
// this should be useful... should be the natural offset
qreal yoffset = (r.height() - rFont.height()) / 2;
// qDebug() << yoffset << r << rFont;
//qreal y0 = (r.height() - fm.height())/2;
p.setColor(Qt::darkGreen);
painter->drawEllipse(10, yoffset, 1, 1);
// where is the font rect
p.setColor(Qt::magenta);
painter->setPen(p);
yoffset = (r.height() + rFont.height()) / 2;
painter->translate(0, yoffset);
painter->drawRect(rFont);
painter->restore();
}
I have also tried not using QGraphicsTextItem, but paint text inside a rectangle. The same thing happens.
(Qt 4.7 - 5.x)
This is not a good solution. This is an attempt to solve my own problem - in a first iteration - of setting text with given width and height, using font metrics.
Reasons for not being good -
Even after resize, text is smaller than desired, I don't understand why
The position is incorrect, based on font style the text can be above or below the canvas, meaning it gets clipped.
I resize it using a factor calculated from the item bounding rect size and the font metrics bounding rect (I used the tight bounding rect for more accurate size).
myText->setItemFontSize(12); // If I use font metrics I need to reset text size on every change, because resizing loses font info
QFontMetricsF fm(myText->font());
QRectF fmRect = fm.tightBoundingRect(myText.toPlainText().toUpper());
// without toUpper() the size is too small - even so it is a bit small
// I read tightBoundingRect is slow - but boundingRect and height and ascent all give values that result in even smaller size
//qreal absH = fm.ascent();
qreal absH = fmRect.height();
qreal absW = fmRect.width();
qreal absHeightRatio = myText->getItemSize().height() / absH;
qreal absWidthRatio = myText->getItemSize().width() / absW;
Then setting size:
myText->setItemSize(QSizeF(absWidthRatio * textLength, absHeightRatio * fontHeight));
// This function scales the `QTransform` on item
// but since I request a final position dependent on item size
// (including blank space around it) - it has no chance of being accurate.....
// This is where my next effort will go, figuring out how to get rid of the fluff
// around the item inside the scaling
The function for setting position: trying to center text:
// leftShift = 10, rightShift = 10 in example
myText->setPos(0,0);
QRectF r = myText->mapToScene(myText->boundingRect()).boundingRect();
QSizeF sz = r.size();
qreal w = sz.width();
qreal h = sz.height();
qreal cx = (m_docLength - w + leftShift - rightShift)/2 - r.left();
qreal cy = (m_docHeight - h)/2 - r.top();
myText->setPos(cx, cy);
The images below are for fontHeight = m_docHeight -
Desirable:
- either the entire size of text (ascent + descent) equals doc height, and text is centered vertically based on content
- or the upper case size text equals doc height and the descent is below document (text centered based on only upper case) - this would seem easier based on how QGraphicsTextItem seems to position it
Actual:
- the text is smaller no matter which parameters I use to scale, and centered based on upper case text
As shown above - I have no idea how I could center vertically based on content (so for edge-to-edge text the descent would fit in) - and in lieu of that, all I really want is edge-to-edge uppercase letters, but I can't seem able to achieve that.
Oh and these are for Arial type font - one of the best-behaved. Other fonts jump all over the place, either above or below the canvas. And for some fonts, the resulting text is actually smaller - which is inexplicable to me, because how can the tight bounding rectangle be smaller than the item bounding rectangle...
Still this is as far as I got to getting my text as close to "true" size and placed on a canvas that matches its size.

Set css from GWT (dynamically) to element with multiple styles associated

I have an instance of TabLayoutPanel where number of tabs would be set dynamically. Therefore to align tabs to fill whole width of the screen I need to
1) Override gwt-TabTayoutPanel default value width 16384px with auto !important (done);
2) Set width of gwt-TabTayoutPanelTab to proper percentage value (e.g. 2 tabs = 50%. 3 tabs = 33%, 4 tabs = 25% and so on).
I have a simple function for that which goes like this (simplified):
Double cssValue = 100.0/getWidgetCount();
(done)
3) Now here goes my question: how can i set the width of gwt-TabTayoutPanelTab from Java? I bolded Tabs because when i use this.getStyleName(); i got in return gwt-TabLayoutPanel not gwt-TabLayoutPanelTab .
In sum, I can divide my question in two:
-how to access TabLayoutPanelTab css class from GWT?;
-how to set said class width with my dynamically generated percentage number?;
EDIT:
Proper edit of function to determine percentage value.
-how to access TabLayoutPanelTab css class from GWT?;
int widgetCount = panel.getWidgetCount();
for(int i = 0; i < widgetCount; i++)
System.out.println(panel.getTabWidget(i).getParent().getStyleName());
}
As you can see there is no direct way to access the tabs. What you can do is access the widgets in the tabs, and get their parent, which is the tab in question.
-how to set said class width with my dynamically generated percentage number?;
If you have a certain amount off possible percentages then you can declare those classes (e.g. custom-Width-25, custom-width-33 etc.) where you specify the width with the !important annotation in order to override everything else.
If the previous solution is not acceptable then you can only use inline css. This means that the element must be already loaded in the DOM. Somewhere in your code where you know that the element is loaded you can call something like this :
int widgetCount = panel.getWidgetCount();
for(int i = 0; i < widgetCount; i++) {
com.google.gwt.user.client.Element tabElement = panel.getTabWidget(i).getParent().getElement();
tabElement.getStyle().setWidth(100/widgetCount, Unit.PCT);
}

How can I autoscale the font size to fit the contents of a div?

I have a div with some text:
<div style="white-space:nowrap;overflow:none;width:50px;">
With some text in it
</div>
How can I scale the font size of the text so all of the text is visible?
Contrary-wise. You could wrap the text in an interior DIV, measure its width with JavaScript. Test if that width is wider than the parent DIV. Get the current font size, and incrementally move it down 1px at a time until inner DIV's width is less than or equal to the outer DIV's width.
I've been doing something like this, to set the text scale relative to the parent (or window) width / height. You can avoid jQuery by using offsetWidth and offsetHeight instead of width.
var setBodyScale = function () {
var scaleSource = $(window).width(), // could be any div
scaleFactor = 0.055,
maxScale = 500,
minScale = 75; //Tweak these values to taste
var fontSize = (scaleSource * scaleFactor) - 8; //Multiply the width of the body by the scaling factor:
if (fontSize > maxScale) fontSize = maxScale;
if (fontSize < minScale) fontSize = minScale; //Enforce the minimum and maximums
$('html').css('font-size', fontSize + '%'); // or em
}
Short Answer: You don't.
You would have to try a size, render it, see if it fits, try another size, render it see if it fits, etc. Then you have to handle the case where the calculated font size is so small no one can read the text.
There are other options, if the text doesn't fit, add an ellipsis (...) to the end of the text, when you mouse over it, the div could expand, you could use a popup window or tooltip with the full text, or put the full text in a larger area of the screen.
Find another way.
Came across this JQuery plugin in my quest to find the same.
Github
Demo
Also came across this Jquery script when I was looking for the same thing. It has the added benefit over the others, as far as I quickly tell, is that it also adjusts for height as well as width.
Comes from here: http://www.metaltoad.com/blog/resizing-text-fit-container
function adjustHeights(elem) {
var fontstep = 2;
if ($(elem).height()>$(elem).parent().height() || $(elem).width()>$(elem).parent().width()) {
$(elem).css('font-size',(($(elem).css('font-size').substr(0,2)-fontstep)) + 'px').css('line-height',(($(elem).css('font-size').substr(0,2))) + 'px');
adjustHeights(elem);
}
}

How to Auto-resize font size to fit text box height / width?

I am trying to have text automatically size its font to fill an entire text component.
My current approach is to set font size as a function of the number of text characters and the text components height and width but I can't find the right coefficients to make this work nicely.
Is there a simpler or more elegant way?
Does truncateToFit work on Text? I read somewhere that it doesn't work well.
Edit: I forgot to mention that I would like it to scale beyond the max font size (which is 127 i believe). How is this done? scaleX?
AS3 sample function. You should call it anytime your TextField's content changes
function Autosize(txt:TextField):void
{
//You set this according to your TextField's dimensions
var maxTextWidth:int = 145;
var maxTextHeight:int = 30;
var f:TextFormat = txt.getTextFormat();
//decrease font size until the text fits
while (txt.textWidth > maxTextWidth || txt.textHeight > maxTextHeight) {
f.size = int(f.size) - 1;
txt.setTextFormat(f);
}
}

Resources