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.
Related
I am using QSplitter to split two widgets but between them, there is a QSplitter sign shown. How can I disable or hide it? Or normally show the cursor as it used somewhere?
I don't want to see this horizontal Splitter as it is not used in the widget.
If you do not need that mouse dragging functionality at all, you can call setWidgetAttribute(WA_TransparentForMouseEvents); on the splitter. I think that should help !?
You must reimplement the protected method QSplitterHandle *QSplitter::createHandle() of your splitter, and inside it, you create your own handler with the desired cursor :
QSplitterHandle *MySplitter::createHandle()
{
QSplitterHandle *handler(new QSplitterHandle(Qt::Orientation::Horizontal /*for example*/, this));
handler->setCursor(Qt::ArrowCursor);
return handler;
}
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 custom QAbstractItemModel used to display information in a QTreeWidget. However, individual indices are drawn using a QStyledItemDelegate. One item that is drawn using the delegate is a pixmap. When the user hovers the mouse over the pixmap (either help event style or hover enter style is fine) I need to do something, what it is isn't important.
So my question is, how can I know when the mouse has hovered over a specific item inside a QTreeWidget, when that item is drawn using a delegate?
In other situations, I could just subclass QLabel, set the pixmap on it, and then do whatever I need in the event() function, but in this case there is no object behind the pixmap, it is just painted onto the screen, so it doesn't actually receive events. Is it possible to use the delegate to paint an actual widget where I want it to so that widget can receive events, or do I have to work around this some other way?
You could subclass QTreeWidget and reimplement the mouseMoveEvent. In the event you can use the itemAt function in order to check if a valid item is at the mouse position and then do what you want.
void MyTreeWidget::mouseMoveEvent(QMouseEvent * event)
{
QTreeWidget::mouseMoveEvent(event);
QTreeWidgetItem* treeItem = itemAt(event->pos());
if (treeItem != NULL)
doSomething(treeItem);
}
You could avoid subclassing QTreeWidget and implement it in the parent widget/main window. Notice however that the itemAt function expects coordinates in the widget's viewport so you should transform the coordinates to tree widget's coordinates. IMHO it is more elegant to subclass it and just implement the mouseMoveEvent function.
EDIT
If you need to detect the position of an icon within the widget item, it is a bit more advanced but you can check my answer to an older question for more details:
Position of icon in QTreeWidgetItem
There is no Qt built-in solution to this problem. The problem can be solved, however, by saving the geometry of the individual items that are painted using the delegate as they are painted. The paint() function, however, has a const modifier so the data structure you use to save the geometry must be mutable. In this case, I don't think this constitutes a breach of the principles of OOP, but is rather a prime example of why the mutable keyword exists and when it should be used.
You then need to subclass QTreeWidget so you can re-implement the mouseMoveEvent() function as webclectic said. Inside that function you can compare the position of the mouse to the geometry of the item that you painted earlier. If the mouse is inside the item, then it is being hovered.
I have implemented Finger Scrolling to one of my QListWidget.
I have taken refernce from
http://www.developer.nokia.com/Community/Wiki/Qt_Kinetic_scrolling_-_from_idea_to_implementation
Now the problem is on_current_row_changed event of QListWidget gets fired when i scroll up and down my List.
How i can avoid this on click only it should behave like click not on Scroll.
Starting from Qt5 this is as simple as:
#include <QScroller>
...
QScroller::grabGesture(myListWidget, QScroller::LeftMouseButtonGesture);
For touch screens use TouchGesture instead of LeftMouseButtonGesture.
If the widget doesn't inherit QAbstractScrollArea (e.g. QWebView):
QScrollArea *scrollArea = new QScrollArea;
scrollArea->setWidget(myWidget);
QScroller::grabGesture(scrollArea, QScroller::LeftMouseButtonGesture);
Be sure to resize the widget to its content size.
You need to test whether the finger has moved between mousePress and mouseRelease. You can extract the position of the press, so if you store it in an intermediate variable, then test it against the position of the mouseRelease (say using QPoint::manhattanLength()), you can tell whether the finger has moved. If it has, the user is scrolling, if not, they're clicking.
EDIT: Looking at the code you've linked to, they're already doing the above. Could we see some more of your reimplemenation?
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).