Enaml Looper horizontal layout - enaml

By default the below code will lay out each GroupBox object vertically stacked (one underneath the other).
enamldef Main(Window):
attr model
Container:
constraints = [ hbox(items) ]
Container: items:
Looper:
iterable << model.l # model.l = some list of atom objects
GroupBox:
title << loop_item.name
CheckBox:
checked := loop_item.active
How can i lay them out in a looper such that they are horizontally stacked (left to right) instead?
I can't find any information on this in the enaml docs / API.

You can either supply your own constraints which do what you want, such as the hbox helper:
https://github.com/nucleic/enaml/blob/master/examples/layout/basic/hbox.enaml#L34
Or use one of the convenience Container subclasses, like HGroup:
https://github.com/nucleic/enaml/blob/master/examples/widgets/h_group.enaml#L46
https://github.com/nucleic/enaml/blob/master/enaml/widgets/h_group.py#L17
The Enaml examples will probably answer a lot of your entry-level questions:
https://github.com/nucleic/enaml/tree/master/examples

Related

How to properly indent (align) overflown row`s label ? - (Ant Design Table, Tree Data)

I am building a custom component where I am using the table component provided by Ant Design. For most of the parts, everything works as expected, however, there is a "tiny" issue.
I am using the "tree-data" (i.e. nested JSON) data to populate the Table component. Due to the fixed column size (which is a requirement) it has been noted during QA that the row`s label is not properly indented if it overflows (i.e. starts on a new row).
So my question is, how can indent the label such that when the label starts on a new line it starts from the initial indentation like this:
The GOAL would be to have the label "squeezed" within the green-dashed container.
On THIS LINK you can find a demo (the same as the one in ant design documentation with minor changes) which replicates the issue I am working on.
open the link
expand the first row (i.e. John Brown sr.) as it is expanded in the picture above.
You can apply display 'flex' to the column
// index.css
.name-column {
display: flex;
}
// demo.js
// column
...
...
...
{
title: "Name",
dataIndex: "name",
key: "name",
className: 'name-column'
},
...
...
...

Restricting the OptionGroup width in Vaadin

I have a couple of OptionGroups with very long captions that run across the width of the page, which looks very bad. I tried restricting the width of the OptionGroup using setWidth and via CSS, and also tried restricting the width of the parent container; all without effect.
So I made a grid layout with an option group in the first column (spanning all rows), and individual labels for the captions in the second column (one per row). However, in case the captions span multiple lines (which they do in my case), this leads to the radio buttons / checkboxes no longer being aligned to the captions. (Regrettably, I'm not allowed to post images.) For instance,
(o) This is a multiline
(o) caption
This is another multiline
caption
I resolved this by creating one OptionGroup per label, and adding each option group in the first column:
(o) This is a multiline
caption
(o) This is another multiline
caption
Clearly, in case of radio buttons, this means multiple buttons can be selected at the same time, since they are no longer linked via a single OptionGroup. Therefore, I registered listeners which, each time a button is selected, de-select all other buttons. And this brings me to my problem; since this "unchecking" is done at the server side, there will unavoidably be some lag, meaning that for some time, multiple radio buttons will appear selected at the client side.
Any ideas on how to resolve this? I only started working with Vaadin recently, so I'm far from an expert. Is there some simple way of restricting the caption width (some magical undocumented CSS class), or do I need to extend / adapt the client-side widget implementation?
Thanks,
William
What you need is FlexibleOptionGroup add-on.
Here is an example implementation:
#Override
protected void init(VaadinRequest request) {
Container cont = new IndexedContainer();
cont.addContainerProperty("caption", String.class, "");
// very long strings in the following setValue() methods
cont.getContainerProperty(cont.addItem(), "caption").setValue("I have...");
cont.getContainerProperty(cont.addItem(), "caption").setValue("So I ma...");
FlexibleOptionGroup fog = new FlexibleOptionGroup(cont);
fog.setCaption("FlexibleOptionGroup:");
fog.setItemCaptionPropertyId("caption");
fog.setMultiSelect(true); // force using CheckBoxes
VerticalLayout fogLayout = new VerticalLayout();
Iterator<FlexibleOptionGroupItemComponent> iter;
iter = fog.getItemComponentIterator();
while(iter.hasNext()) {
// OptionGroupItem part (CheckBox or RadioButton)
FlexibleOptionGroupItemComponent fogItemComponent = iter.next();
// CustomComponent part
Label caption = new Label(fogItemComponent.getCaption());
caption.setWidth(400, Unit.PIXELS);
fogLayout.addComponent(new HorizontalLayout(fogItemComponent, caption));
}
setContent(fogLayout);
}
The above code produces:

Make two QDockWidgets mutual execlusive at the same position

I have two QDockWidget's, only one of them is visible at the time, I manage that by toggleViewAction().
What I need to do is that I want the two QDockWidget's to be in the same location, with the same size and docked at the same dockWidgetArea with the same orientation and order relative to other QDockWidgets.
I did most of the that by this code:
void myMainWindow::slotToggleDocks(QAction* action) {
if(action == viewDock1) {
Dock1->setFloating(Dock2->isFloating());
Dock1->resize(Dock2->size());
Dock1->restoreGeometry(Dock2->saveGeometry());
Dock1->move(Dock2->pos());
addDockWidget(dockWidgetArea(Dock2), Dock1);
...
Dock2->hide();
} else if(action == viewDock2) {
Dock2->setFloating(Dock1->isFloating());
Dock2->resize(Dock1->size());
Dock2->restoreGeometry(Dock1->saveGeometry());
Dock2->move(Dock1->pos());
addDockWidget(dockWidgetArea(Dock2), Dock1);
...
Dock1->hide();
}
}
this code make the two have the same location and size and docked to the same area (left, right, ...) but it doesn't guarantee that the Docks will have the same layout with the other QDockWidget's in the same dockWidgetArea.
Meaning if this was the before layout:
Layout before http://holmez.net/qdockwidget/1.png
This is after toggling:
Layout after toggling http://holmez.net/qdockwidget/2.png
This is what I want:
Expected result http://holmez.net/qdockwidget/3.png
I managed to do that by a simple trick, add this line of code:
splitDockWidget(Dock1,Dock2,Qt::Horizontal);
before hiding Dock1, and this line:
splitDockWidget(Dock2,Dock1,Qt::Horizontal);
before hiding Dock2.
This fixed the problem of the arrangement of docked widgets, not sure if this is the best way but it works for me.
What about only using 2 QDockWidgets, but having QStackedWidgets INSIDE of them which you can use to swap views? That's what I'm currently doing, and it works great.
Another advantage is that swapping views is as simple as:
stackedWidget->setCurrentIndex(index);
What about using QTabWidget?
The 2 widgets will have to be in the same Qt::DockWidgetAreas

Need to display the widgets inside my QListWidget with an offset, basically shifted a bit to the right

I have a panel.ui file done using QTDesigner. It's a QFrame class, rectangular shape with few labels on it. And I have a QListWidget class where I insert 3 instances of the panel.ui.
I create a QListWidgetItem and then use List->SetItemWidget(..) to populate my list.
The Result is a list filled with three panels. I was also able to move the panels inside the list using dragDropMode internalMove.
I also tested the ability to shift the panels a bit to the right when I click on them and that worked:
in procedure List::mousePressEvent(QMouseEvent *event)
Panel *child = static_cast<Panel*>(childAt(event->pos()))
...
int y= child->pos().y();
int x = child->pos().x();
child->move (x +10, y); `
Problem: When I run the app and display the list, I want all the panels to be displayed with that 10 offset to the right. So in the List constructor and inside the loop after this->setItemWidget(myPanelItem, myPanel); I try using myPanel->move() like above but it doesn't seem to work.
I run the app, the panels are displayed without my offset ( not sure why?) but when I click on one, it shifts.
move() won't work reliably since the widgets are in a layout. (Well, not a layout as in a QLayout, but the effect is comparable: When any metric in your application changes, e.g. you resize or scroll the list, the widgets are repositioned by the list widget.)
What you can do is wrap your actual widget in a container widget with a layout margin:
QWidget* wrapIntoContainerForOffset(QWidget* widget, int offset /*in pixels*/) {
QWidget* container = new QWidget;
QHBoxLayout* layout = new QLayout(container);
layout->setContentsMargins(/*left=*/ offset, /*others=*/ 0, 0, 0);
layout->addWidget(widget);
return container;
}
Then you add these containers to the listwidget instead.
Have You tried StyleSheets. The QListWidget supports Box model( http://doc.qt.digia.com/qt/stylesheet-customizing.html#box-model ). So You may want to try playing around with margins in the stylesheets.
Style sheet reference: http://doc.qt.digia.com/qt/stylesheet-reference.html

fixing child layout/widget position in QT

I wanted to know whether is there any way of fixing child layouts within a parent layout. For example...
QVBoxLayout *vbox = new QVBoxLayout;
// adding pushbuttons/layouts...
vbox->addWidget(one);
vbox->addWidget(two);
vbox->addWidget(three);
vbox->addWidget(four);
Now this ends up as four buttons/layouts in a vertical layout in the sequence that they are added. But if I remove buttons/layouts "one", "two" and "three"...
vbox->removeWidget(one);
vbox->removeWidget(two);
vbox->removeWidget(three);
After doing this, the pushbutton "four" will move up the layout as you remove widgets on top of "four". I don't want this to happen.
Is there any way that even if I remove the widget/layout on top, I need that last widget/layout to stay where it is currently.
How do I achieve this ?
UPDATE: Well I was experimenting and I was kind of able to achieve what I wanted using QGridLayout. Here is the code, but I am using QGridLayout instead of QVBoxLayout.
connect(one,SIGNAL(clicked()),this,SLOT(remove_btns()));
g = new QGridLayout(this);
g->addWidget(one,0,0,1,2);
g->addWidget(two,1,0,1,2);
g->addWidget(three,2,0,1,2);
g->addWidget(four,3,0,1,2,Qt::AlignBottom);
setLayout(g);
If I delete the above three buttons, the fourth one stays where it is, because of QT::AlignBottom , it does not work without that thing.
Here is the SLOT remove_btns()
void test::remove_btns()
{
g->removeWidget(one);
g->removeWidget(two);
g->removeWidget(three);
delete one;
delete two;
delete three;
}
When I click "one", top three buttons vanish, and the fourth one stays where it is. But it does not work if I don't give the QT::AlignBottom . Also, these alignment things are a mystery to me, I am unable to find how exactly they work.
This is definitely NOT an answer..., because I don't understand how it worked :P
If you are immediately replacing the widgets you removed, you can always insert your new widgets by index.
void insertWidget ( int index, QWidget * widget, int stretch = 0, Qt::Alignment alignment = 0 )
Yes, just hide the widgets instead of removing them:
one->hide();
two->hide();
three->hide();
If you really have to remove the widgets, perhaps you can replace them with some lightweight widget like a QLabel with no text.

Resources