How to Drag and Drop Custom Widgets? - drag-and-drop

I have created my own custom widget and I want to support internal drag and drop for the widgets.
I have added 4 of my custom widgets in a vertical box layout. Now i want to drag and drop the custom widgets internally. To be more clear, If i drag the last widget and drop it in the first position, then the first widget has to move to the second positon and the last widget (which is dragged) has to move to first position. (same like drag and drop of the items in the List view). Can anyone suggest me a way to drag and drop of the custom widgets.

You need to reimplement mousePressEvent, mouseMoveEvent and mouseReleaseEvent methods of a widget you want to drag or install an event filter on them.
Store the cursor position in mousePressEvent and move the widget in mousePressEvent to the distance the cursor moved from the press point. Don't forget to clear the cursor position in the mouseReleaseEvent. The exact code depends of how you want the widget to look when is being dragged and how other widgets should behave when drag/drop the widget. In the simplest case it will look like this:
void mousePressEvent(QMouseEvent* event)
{
m_nMouseClick_X_Coordinate = event->globalX();
m_nMouseClick_Y_Coordinate = event->globalY();
};
void mouseMoveEvent(QMouseEvent* event)
{
if (m_nMouseClick_X_Coordinate < 0)
return;
const int distanceX = event->globalX() - m_nMouseClick_X_Coordinate;
const int distanceY = event->globalY() - m_nMouseClick_Y_Coordinate;
move(x() + distanceX, y() + distanceY());
};
void mouseReleaseEvent(QMouseEvent* event)
{
m_nMouseClick_X_Coordinate = -1;
}

Related

Build and add children in performLayout

I'm making a skill tree package and I'm wanting to have a robust api for users to alter the appearance of edges between nodes. For that, I want the signature of an edgeBuilder to contain some layout information of the from and to nodes it connects. For example, I could pass through to the builder the angle an imaginary straight line from one node to another makes. This angle could then be used to rotate the widgets I have at the ends of edges to properly look like they're pointing at the right things (in the image below, I have a triangle clipper that is just always pointed down).
I have this structure for laying out the children (both edges and nodes) inside my multi-child custom RenderObject.
#override
void performLayout() {
// ...
final skillNodeLayout = delegate.layoutNodes(
loosenedConstraints,
graph,
nodeChildren,
);
size = skillNodeLayout.size;
// ...
delegate.layoutEdges(
loosenedConstraints,
skillNodeLayout,
graph,
edgeChildren,
nodeChildren,
);
}
But now I'm curious to know whether Flutter advises against building and adding widgets in the layout phase. The ContainerRenderObjectMixin I'm mixing in specifically has methods to add to the list of children such as adoptChild(child) or addAll.
Can I avoid passing through the edge children to the RenderObject constructor and instead pass them through as a plain list of builder functions I call after the node layout and then add to the RenderObject? Something roughly like this:
#override
void performLayout() {
// ...
final skillNodeLayout = delegate.layoutNodes(
loosenedConstraints,
graph,
nodeChildren,
);
size = skillNodeLayout.size;
final edgeChildren = edgeChildrenBuilders.map((builder) {
return builder(skillNodeLayout);
}).toList();
// Found in the `ContainerRenderObjectMixin`
addAll(edgeChildren);
delegate.layoutEdges(
loosenedConstraints,
skillNodeLayout,
graph,
edgeChildren,
nodeChildren,
);
}
My worry is that it keeps adding children to the RenderObject every time a performLayout is requested or that this was never the intended way to work with renderObjects.

SWT eclipse, remove a PainItem listener that was used to draw a table or tree table

I have used a PaintItem event listener (org.eclipse.swt.PaintItem) to draw a table tree. But that listener is always get called when i mouse over or select something on table. I want to remove that listener once its all painted or done with table rectangle draw. Please help. Below is the code snipped I am using:
Listener l = new Listener() {
public void handleEvent(Event event) {
event.gc.setForeground(EclipseSupport.COLOUR_DKGRAY);
event.gc.setLineWidth(2);
int currentCol = event.index;
Rectangle rect = ((TreeItem) event.item).getBounds(currentCol);
event.gc.drawRectangle(rect);
}
};
tree.addListener(SWT.PaintItem, l);

javafx: How can I put slider tick labels above its sliding track in horizontal slider?

I am trying to customize the horizontal slider such that its major tick labels appear above sliding track (by default they appear below sliding track) and major tick label values appear in reverse order. Do I need to use CSS somehow to display the labels above sliding track?
So far I have reversed the labels ordering using setLabelFormatter:
final double sliderMax = slider.getMax();
slider.setLabelFormatter(new StringConverter<Double>() {
#Override
public String toString(Double d) {
return String.valueOf((int)(sliderMax - d));
}
#Override
public Double fromString(String str) {
return (sliderMax - Double.parseDouble(str));
}
});
Any pointers will be helpful.
This is certainly possible with CSS.
This will only work for horizontal Slider though. Theoretically there is the pseude CSS class horizontal on the Slider which could be used to restict the CSS to horizontal Sliders, but I was unable to test this, maybe you can make it work.
Check out the CSS-Refrence and inspect your application with ScenicView.

How to slide a listview by interacting with seekbar

I have a listview and a seekbar, i want the listview to react accroding to the interaction with the seekbar.
For ex :- if the seekbar is dragged to either ends, the listview should automatically go up or down.
Any help is greatly appreciated.
You should be able to use the list view method:
smoothScrollToPosition(int)
and OnSeekBarChangeListener
Set an OnSeekBarChangeListener on your seekbar.
In onProgressChanged add code using smoothScrollToPosition to update the listvew position.
Something like this:
public void onProgressChanged (SeekBar seekBar, int progress, boolean fromUser) {
listView.smoothScrollToPosition(progress); //assuming you have a 1 seekbar position for each row in the list, otherwise you'll need to do some calculation to compute the new list view position.
}
alternatively, you could use the onStopTrackingTouch method if you only want to scroll to the final position the user touched in the seekbar.

Auto scroll a gtkscrolledwindow

I have a form interface with a large number of horizontal drop down and text boxes that are inside a GTKscrolledWindow. The form has to be aligned horizontally because there are an unlimited number of forms in the window (think tabel of forms).
Is it (possible/how do I) auto-scroll the GTKScrolledWindow to the right when the operator tabs to the next form control which is off to the right of the screen.?
Related question would be how do I detect if the focused element (button etc) is visible in it's parent scrolledwindow.
Thanks.
I hope you don't mind I am using GTK+ C API in the description, the sollution could be converted to the PyGTK easily and the principles remains the same.
Starting with the second question - if you know which widget to test, you can detect its visibility by calling gtk_widget_translate_coordinates(child, parent, 0, 0, &x, &y) to get the position of the child relative to the parent. By gtk_widget_get_allocation() you get the size of parent and child and you simply test if whole child rectangle is in the scrolled window.
gboolean is_visible_in (GtkWidget *child, GtkWidget *scrolled)
{
gint x, y;
GtkAllocation child_alloc, scroll_alloc;
gtk_widget_translate_coordinates (child, scrolled, 0, 0, &x, &y);
gtk_widget_get_allocation(child, &child_alloc);
gtk_widget_get_allocation(scrolled, &scroll_alloc);
return (x >= 0 && y >= 0)
&& x + child_alloc.width <= scroll_alloc.width
&& y + child_alloc.height <= scroll_alloc.height;
}
You can obtain the curently focused widget in window by gtk_window_get_focus () or you can detect it when focus is changed.
In the autoscroll problem you can handle "focus" signal connected to the widget which can be focussed or the "set-focus-child" event connected to the container containing the widgets. In the signal handler you should check, if the focused widget is visible. If not, determinate its position and scroll properly.
To do so you have to detect the position of the widget inside the whole scrolled area. If you are using some container which does not support scrolling (such GtkHBox) iside GtkScrolledWindow (adapted by viewport), you can get the coordinates of the focused widget relative to the container by gtk_widget_translate_coordinates() again - now using the container instead of scrolled window. The value of the adjustment, if using GtkViewport, the adjustment value correspond to the position in pixels in the scrolled area, so setting adjustment value to x relative coordinate will do scrolling. So the important part of the handler could be
GtkWidget *scrolled = /* The scrolled window */
GtkWidget *container = /* The container in the scrolled window */
GtkWidget *focused = /* The focused widget */
GtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment(
GTK_SCROLLED_WINDOW(scrolled));
gint x, y;
gtk_widget_translate_coordinates (focused, container, 0, 0, &x, &y);
gtk_adjustment_set_value(hadj, min(x, maximal adjustment value allowed);
The maximal adjustment value allowed is adjustment.upper - adjustment.page_size. The focused widget is passed as signal handler argument for both signals, in the case of "set-focus-child" signal you get also the container as argument.
Here's what I did, based on Michy's answer.
To make a scrolled window auto-scroll, run in the constructor:
FocusScroll(scrolledwindow).
class FocusScroll(object):
"""
Get a gtk.ScrolledWindow which contains a gtk.Viewport.
Attach event handlers which will scroll it to show the focused widget.
"""
def __init__(self, scrolledwindow):
self.scrolledwindow = scrolledwindow
self.viewport = scrolledwindow.get_child()
assert isinstance(self.viewport, gtk.Viewport)
self.main_widget = self.viewport.get_child()
self.vadj = scrolledwindow.get_vadjustment()
self.window = self.get_window(scrolledwindow)
self.viewport.connect('set-focus-child', self.on_viewport_set_focus_child)
def get_window(self, widget):
if isinstance(widget, gtk.Window):
return widget
else:
return self.get_window(widget.get_parent())
def is_child(self, widget, container):
"""
Go recursively over all children of container, to check if widget is
a child of it.
"""
for child in container.get_children():
if child is widget:
return True
elif isinstance(child, gtk.Container):
if self.is_child(widget, child):
return True
else:
return False
def on_viewport_set_focus_child(self, _viewport, _child):
idle_add(self.scroll_slide_viewport)
def scroll_slide_viewport(self):
"""Scroll the viewport if needed to see the current focused widget"""
widget = self.window.get_focus()
if not self.is_child(widget, self.main_widget):
return
_wleft, wtop = widget.translate_coordinates(self.main_widget, 0, 0)
wbottom = wtop + widget.get_allocation().height
top = self.vadj.value
bottom = top + self.vadj.page_size
if wtop < top:
self.vadj.value = wtop
elif wbottom > bottom:
self.vadj.value = wbottom - self.vadj.page_size
First, the first.
How do you detect the focus ? You connect to GtkWidget::focus signal.
And in that callback you can scroll the window to whereever you like, how to do that, you need to get the GtkAdjustment of GtkScrolledWindow and move it accordinly to show what you want.