I have an application that will add a Widget to an HBox, which is contained in a ScrolledWindow. When a Widget is added, I would like the parent ScrolledWindow to scroll to the right, where the newly added Widget is. Adding the widget works just fine, my problem is:
How can I make the ScrolledWindow move when a child is added?
My Vala code looks something like:
private void addView() {
var widget = this.createWidget();
this.box.pack_start(widget); // this.box is a HBox
widget.show_all();
var adj = this.parent_win.get_hadjustment(); // parent_win is a ScrolledWindow
adj.set_value(adj.get_upper());
}
The behavior I am getting now is the adjustment will work every other double click (what signals all this). I would like for the adjustment to occur on every double click.
update I have seen this: Gtk, How to scroll at bottom of viewport list? , but there is no real definitive answer given. you mean to tell me i have to set a 1 sec timeout to scroll ?
Use an idle callback instead of a timeout, and use the GtkContainer::add signal to get notified when a new child is added (http://developer.gnome.org/gtk/unstable/GtkContainer.html#GtkContainer-add).
Related
I have a scroll Pane with a rectangle inside the scroll Pane.The rectangle can only move left or right . The scroll pane has a with of 800,when the windows gets to small the scrollbar becomes enabled and you can scroll. My problem is when i try to move the rectangle when the scrollbar is on , the scroll bar will also move either left or right.Is the a way to temporary disable the scroll feature when i am moving the node >
I think what you might be looking for is
public final void setPannable(boolean value)
Sets the value of the property pannable.
Property description:
Specifies whether the user should be able to pan the viewport by using the mouse. If mouse events reach the ScrollPane (that is, if mouse events are not blocked by the contained node or one of its children) then pannable is consulted to determine if the events should be used for panning.
https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ScrollPane.html#setPannable-boolean-
I'm not sure if this works, but sounds like it.
You also could use https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Node.html#onMouseClickedProperty
or a similar MouseProperty, set up a Listener and make it so that when you click on the ScrollPane, it will set https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ScrollPane.ScrollBarPolicy.html
to NEVER
public static final ScrollPane.ScrollBarPolicy NEVER
Indicates that a scroll bar should never be shown.
then back to your original setting for ScrollPane.onMouseReleased();
Good luck!
Just as a QPushButton provides a default clicked() signal, I expected QScrollArea to have a sliderChanged() or similar signal. Interestingly, the QScrollBar does have such a signal.
All I would like to do is to know what part of the huge widget inside the scroll area is visible, whenever the user scrolls it.
There are many solutions, none of which seem elegant to me:
subclass QScrollArea
subclass the widget inside the scroll area, and re-implement its paint event.
create a custom veiwport, using QScrollBar
periodically poll the position of the widget inside the scroll area. This seems to be the worst solution.
Is there a way without subclassing?
There is QAbstractSlider::valueChanged() signal that is emitted when the slider value has changed, with the new slider value as argument. This will notify you as soon as you scroll your view.
WRT the second problem, neither of mentioned points necessary. You need to:
1) Get the position of inner widget (if any) related to the scroll area:
QPoint p = scrollArea->widget()->pos();
It use to be a negative coordinates if you scrolled your view down/right or null without scrolling.
2) Get the size of the visible area
QSize s = scrollArea->viewport()->size();
With these two values you can construct a QRect that will represent the visible area of your inner widget.
I have a class that uses a vertical QSplitter to separate two important widgets (the arrow pointer is at the splitter position):
The upper child widget is a QTextEdit while the lower child is a custom widget that interacts with my app's tagging system. The lower child is collapsed by default; it is only displayed when the user clicks the tag toolbar button or drags the splitter upward. When the button is toggled on, the lower child is displayed, otherwise it remains hidden.
The toolbar button works perfectly but right now I have no way to detect when the user collapses the lower child by dragging the splitter bar all the way down. This causes the toolbar button to stay toggled on when the user collapses the lower child by hand. The inverse is also true; when the user drags the splitter up the button stays off.
I've already tried connecting the QSplitter:splitterMoved(int pos,int index) signal to a slot that un-toggles the button when the lower child (index 1) is collapsed (pos 0) manually but for some reason the signal never gets emitted.
My code (the splitter object is called divide) connects this signal...
connect(divide, SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int pos, int index)));
... to this slot:
void Editor::splitterMoved(int pos, int index){
using namespace std;
if((index==1) && (pos==0)){
ui->TagButton->setChecked(false);
}
else{
ui->TagButton->setChecked(true);
}
}
Am I using this incorrectly? The slot currently does nothing no matter what I do to the splitter. Is there a better way to solve this problem?
Are you sure parameter names are allowed in the SLOT macro? A quick test suggests they're not.
Try with:
connect(divide, SIGNAL(splitterMoved(int,int)),
this, SLOT(splitterMoved(int,int)));
UPDATE:
Another point is that pos is not 0 when the child widget #1 is collapsed, on the contrary it reaches its maximum value, since it is the distance from the top. Testing QSplitter:sizes() would be easier.
Example, assuming divide is a class member:
void Editor::splitterMoved(int pos, int index){
if(divide->sizes().at(1)==0) {
ui->TagButton->setChecked(false);
}
else{
ui->TagButton->setChecked(true);
}
In the case of QSplitters you can check a child widget's invisibility using:
QWidget::visibleRegion().isEmpty()
Unlike checking whether the handle is at zero this works for both extremes.
I have QMdiArea object in QMainWindow which I did not have set with setCentralWidget() but as mentioned below.
MainWindow::createMdiArea() {
QMdiArea mdiArea = new QMdiArea(this)
mdiArea.setGeometry(0,0,1024,600);
mdiArea.show();
}
I don't want to set this QMdiArea as the center widget. Now I am creating some child windows inside this QMdiArea, as following
MainWindow::createChildWindow()
{
HelpWindow child1 = new HelpWindow(). // HelpWindow is a very simple class derived from QWidget and containing one QLineEdit.
mdiArea.addSubWindow(&child1);
// Set the geometry of Child widget.
child1.parentWidget()->setGeometry(0,0,400,100); // Setting geometry which I have saved.
child1.show();
}
So far so good. But the problem is in the child window resize / close events I need to save the size of the HelpWindow and I am doing following to save the size of the child window in its resize / close events.
saveHelpWindowSize(size());
saveHelpWindowPos(pos());
Ok. Here comes the problem. The size I have got from the size() function inside the child window is different from the one which I have used in setGeometry() function, even I see it in some method other than resize event (i.e Close event).
So, Suppose first time the child window was created with the size (using setGeometry) 400, 200, when I go to close this window the size I will get from HelpWindow::size() might be say (385, 190) which I will save, and next time setGeometry() will get this size from settings, and at this time on close event I will get more smaller size, and eventually my child window will have size (0, 0).
1: Any thoughts on how to sync both these sizes (i.e., the size if the child widget being set by setGeometry() function and the size of the widget I am getting from size() function of the widget)
2: Another question, I am receiving resizeEvent / closeEvent events etc in the child widget (HelpWindow) class, but I am not getting moveEvent when I move the child window inside QMdiArea, the only time I receive this event is when I maximize the child window inside QMdiArea (which I won't be doing). So I need to save the position of my child window when its position is changed. How can I do it?
I'm working on a Configuration QDialog. It has several categories (General, Appearance, etc.) that get loaded when the user clicks on them. Each category has its own page. These pages are separate classes in their own right (each has its own ui, cpp, and h). When the Preferences window loads, the pages get instantiated and are loaded into a QStackedWidget. The Stackedwidget is then placed into a QScrollArea so it can scroll if necessary.
However, there is a problem. Ever since I added the QStackedWidget, the QScrollArea always has a vertical scrollbar even when the current page is short enough not to need one: (picture shows the shortest page)
The ScrollArea vertical scroll policy is set to Qt::ScrollBarAsNeeded so logically it should only show a bar if the page is larger than the viewable area.
Here's what I already tried to fix this:
Setting the scroll policy to Qt::ScrollBarAlwaysOff. While this gets rid of the scrollbar, its unacceptable since it doesn't let the user know they need to scroll on long pages.
Setting the Minimum/Maximum heights for the QStackedwidget. This makes the scrollbar go away if I set it for a low enough value, but it is unacceptable since it causes some of the widgets to have a squished appearance.
I know the problem has something to do with the QStackedWidget but since this is the first time I've used QStackedWidget I’m not sure what it is. I've also noticed the scroll is always for the same amount; i.e. the scrollable area is always the same size no matter how large/small the page widget is. For some reason, it's slightly larger than the longest page. At first I thought the vertical spacers I put at at the bottom of each page to tighten up the layout were causing this, but taking them out didn't fix it.
Update: Here's the code that controls the Stackedwidget:
void Newconfig::on_Categories_currentItemChanged(QTreeWidgetItem *current)
{
QModelIndex index=ui->Categories->currentIndex();
int idx=index.row();
QString category=current->text(0);
this->setWindowTitle("Preferences -- " + category);
if (stack->currentWidget() != 0) {
stack->currentWidget()->setSizePolicy(QSizePolicy::Ignored,
QSizePolicy::Ignored);
}
stack->setCurrentIndex(idx);
stack->currentWidget()->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
adjustSize();
}
The QStackedWidget takes the size of the largest widget added to it. In your case, the largest page in your preferences dialog is what is influencing the size of the QStackedWidget and is thus forcing the scroll area to show its scroll bar, even when it doesn't appear to be necessary.
To get around this, you can create a slot that is triggered right before you change the current widget in the QStackedWidget that sets the size policy of the page you are leaving to QSizePolicy::Ignored and the size policy of the page you are about to show to whatever you desire for that page -- QSizePolicy::Expanding for instance. An example of this technique is detailed on this page. There's a lot of code in the example, but the important part is here:
void changeCurrent(int idx)
{
if (stackWidget->currentWidget() !=0) {
stackWidget->currentWidget()->setSizePolicy(QSizePolicy::Ignored,
QSizePolicy::Ignored);
}
stackWidget->setCurrentIndex(idx);
stackWidget->currentWidget()->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
adjustSize();
}
This function is called to change the current index on the QStackedWidget. It causes the page that was just being viewed to have a size policy that has no influence on the overall size of the QStackedWidget and the page that is about to be viewed to have a size policy of consequence.