I have a container with columns, in each column a different container. Now I want to click on a container (column item) and do something with that container.
Is it possible to create a click (tap) event on a container?
Or (which I like to avoid if possible) do I have the make a custom widget from this container?
You can add a tap handler to any widget through extension (see https://developer.fyne.io/tutorial/extending-widgets). Your custom widget would embed an existing one and just add the Tapped method to enhance it. This avoids making a completely custom widget.
This is the design of Fyne - enhancement through extension instead of every widget implementing every possible combination of events.
Related
I am creating my own GUI in OpenTK.
I want to fire a mouse event when the cursor is, for example, in one of the GUI controls. How can I do that? Because now I'm just iterating through a list of items in the main class, and in the Opentk´s window´s MouseMove event I'm just checking if the mouse coordinates are within the "region" of the component I'm drawing.
This works for now, but I think it could be done in a better way. This way my code is unordered and in the main class, and I would rather have it in the specific component class.
What I would like is to have an event attached to each component of my GUI, so that I can define many events for one component.
I mean, I would like to have for example a button component where I can override or just use a method that fires when an event occurs. Same as OpenGL´s window where you can override events.
This is not a complete answer, because your question is quite broad, but I hope it helps.
In order to implement such a system, here are the core components for a potential design:
UI Components: Some kind of standard interface where different component types can define logic for interactions. Depending on the language, the most common approach is probably something like a parent class Component, with methods to be overridden. These would probably include things like:
Mouse Hover
Mouse Click (press / release)
Click drag
It will also likely need some additional associated information:
Some way to determine the component's location. Could be providing a bounding box, or perhaps a method that tests if a given point is within this component or not.
Information or functionality for drawing the component.
Display and layering settings (is it visible or hidden, should it draw on top of other components or behind).
UI Context: The context is a structure that defines the set of components that are existent in the UI. This could be something like a list structure of Components. In order to build your UI, you would add components to this context. The context will define some behaviour:
Managing components (add / remove / modify).
How to draw the entire context (for example, looping over each component and executing the draw functionality for each).
Handling of events (see next section)
Event Dispatch: To make your UI usable, you can insert an "adapter" layer that handles events from your windowing library (OpenTK) then translates them into usable events for your components and dispatches them. Here is an example of how this might work for a "click" event (pseudo-code):
function TK_Event_ClickPressed(point) {
for component in context {
if component.ContainsPoint(point) {
component.EventClickPressed()
}
}
}
This is actually the more tricky part of the design, in my opinion, because there are some tricky conventions around how component based UI works. You don't necessarily have to follow them, but they're important to be aware of at least because it is probably how people expect your UI to work:
After click press, click drag continues to occur until click release, even if the cursor leaves the component area.
"Actions" occur on click release.
Click release only takes action if the corresponding click press occurred on the same component.
The click release doesn't take any action if the cursor is no longer inside the component (leaving and re-entering the component before release still does the action, though).
You can only be actively clicking one component at a time (the one shown on top), even if multiple components overlap at that spot.
Assuming that you follow these conventions, this means that dispatching events is actually a bit more complicated than just checking if the event point was in a given component or not. You need to maintain some kind of state to keep track of whether the context is currently in a click or not, and which component, if any, is "consuming" the current click. That is, which component should be given the click release and drag events if they occur.
With these systems in place, you just need to create a window, create a UI context, register the adapter layer to the window to act on that context, set up the window to draw the context on frame, then use the context to add / remove / modify components in your program.
I would like complex button, which has several text elements and which should change their state and color depending on button state.
Unfortunately, I see that Xamarin button has only predefined image and text parameters.
How to have multiple controls inside a button in Xamarin?
Visual state manager(Only XF 3.0+) have three states: normal, disabled, focused which is named "CommonStates", or you can create custom states.Maybe it could help:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/visual-state-manager
I think you must read more in content view, where you can add labels into stacklayout or grid with your own api bindable property, then use it wherever you want in your code:
https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.contentview
I have a UI in Codenameone where a container contains another container which contains some widgets. On the bottom level container I'm able to receive pointerDragged events but not pointerPressed. These (pointerPressed) seem to be consumed by the widgets on the top of the hierarchy, but not move down to the bottom container.
How can I fix this?
I'd like to do this to detect left-right swipes on the bottom container. Is there perhaps a better way to do that?
Only focusable components receive the events directly in Codename One otherwise we would have to deliver events to multiple components which might inhibit performance.
The best way to do this is to use an existing component, e.g. Tabs supports swiping and hiding the tabs so you can just use that.
Making the Container focusable is probably not as desireable (although possible) since it might make interaction with the components within difficult.
You can use a pointer listener on the parent form as the Tabs component does internally. This should always work since the form gets all the events: https://github.com/codenameone/CodenameOne/
When i use the following to create a button
NSWindow.standardWindowButton(NSWindowButton.ZoomButton, forStyleMask: 0)
I get a button that doesn't react to mouse hover events. I can augment this by creating a container view with a NSTrackingArea and manually triggering the highlight method but it produces a clicked state.
Is there a way to somehow force the button into the expected behavior state without the darkened background?
I have been trying to avoid subclassing NSButton, but it seems like i may have to, and I'm just in a state of denial.
I could not get this working for the life of me so my solution was to write my own custom buttons. This works fine for me because my NSWindow is already custom so there wont be a clash of style.
https://gist.github.com/icodeforlove/a334884e59784b4c2567
Another viable solution is to use https://github.com/indragiek/INAppStoreWindow as #xhruso00 mentioned, but it seemed like overkill.
I have a composite widget that contains a disabled TextArea on an AbsotutePanel. Now I want to be able to drag the composite widget, starting from anywhere on it, including the disabled text area.
Is that possible?
If you want to drag a composite widget, you need to have a reference to the "drag handle" wich is one of the elements in the composite widget that implements HasAllMouseHandlers. The easiest (and in my mind, cleanest) way to do this is to have the composite widget extend the interface HasDragHandle wich requires the composite to have the method:
Widget getDragHandle(); the interface does not explicitly tell you so but the returned widget must be a widget implementing the HasAllMouseHandlers interface (or you'll get a runtime error).
(Non-composite widgets implementing HasAllMouseHandlers can be used directly)
I'd reccomend using a Label as a drag handle (it doesn't need to contain any text it could just be styled so the user understands it can be used for dragging), and not a form element because then you're overloading it's behaviour in a way the user most likely won't expect. I'm not really sure how a disabled element would work as a drag handle, quite possibly disabling an element will stop any mouse listners from working to so it won't work as a drag handle (haven't tried it though).
Or, try putting your widget into a FocusPanel, which is already enabled for drag 'n drop anyway. I've done this with a TextBox and a button, and it seems to work fine. Disabling the widget inside of the FocusPanel also keeps it from accidentally being activated.