-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend the main window #5489
Comments
There are callbacks on the app.Lifecycle() API (what you're looking for is SetOnEnteredForeground). Fyne uses callbacks because it is what makes most sense for GUI toolkits where most things happen in response to events. |
It is true that Lifecycle has I'm going to formulate the issue in a much more general way below, but it might be something that should be discussed elsewhere, instead of a github issue. Please let me know if there is a better place for discussing it.
I wish it was the case, but in many cases fyne uses interfaces that provide the properties, without callbacks. Because of this, they must be extended. It is cumersome and sometimes impossible. For example, Let's say that I want to create a widget that needs to execute code when another (general) widget changes size or position. If I have an arbitrary wiget (let's say a reference to a The idiomatic solution is to extend the widget. My goal is general: respond to resize event of a general widget. It is generalized using an interface ( Developers of custom, general purpose components should have the ability to hide internal structures, and force the end user to initialize the custom component with a custom initializer. I have no problem with that. But it should not prevent the end users from responding to GUI events that are related to the implemented interfaces. The sad fact is that it does prevent that. :-( What I'm trying to say is that, if there is an interface that is common to a set of widgets, then it should be possible to get notified about events related to that interface, regardless of the concrete implementation. Fyne, and many other GUI toolkits are based on events. It would be essential to be able to respond to events. But it seems to be impossible. For example, A good solution would have the following characteristics. Given a interface (for example
At this moment, I think this is impossible to do with fyne. I'm new to fyne, and I might be missing something fundamental. Without a good solution, it is also impossible to develop new, general purpose components independently that work together. The successful interoperability of general purpose GUI components requires two-way communication between the components, based on their interfaces, using events. I found a general workaround that -- given a reference to an arbitrary widget -- allows me to respond to resize/show/hide etc. events:
How cumbersome it is:
In the process, lots of new problems are introduced:
|
I think there is a slight misunderstanding of our API design and how widgets work here. You should not be using the size of a window to do anything with a widget - this is leaking scope and will make the widgets unable to be used in different contexts. The Layout of a container will decide how to allocate space and widgets will always fill the space they have. A widget can "respond" to size changing because its render Layout method will be called when it changes. The cumbersome workaround you describe above sounds like a complicated way to write a custom layout - which is just two methods, MinSize and Layout. https://docs.fyne.io/extend/custom-layout |
If you want to do wrapping without type knowledge you should check out the wrapper types in the fyne-x repo. |
I'm not sure what a leaking scope is, but I disagree. I can come up with good examples where the Window size is needed, and should be used to do lots of things. For example, what if I want to create a different layout in landscape and in portrait mode? Are you saying that this is something that I should not do? Or maybe I misunderstood. The issue is more general than tat. I cannot easily write code that responds to size changes of any other widget (not just Window).
Yes, but you are talking about a static interface that has fixed layouts and widgets. Many applications are changing their layouts and widgets on-the-fly, and in most cases, it requires running code for events like hidden, shown, size changed, position changed. And yes, layouts can lay out widgets, but what if I want to do something that goes beyond that? E.g. change the layout on one part of the app when size changes on another part of the application. |
Extending the window is not the right solution in any way. However, we should consider expanding the lifecycle API with more callbacks where it makes sense. |
Different layouts for landscape and portrait are possible with layouts. The Layout call is told what space is available and it can switch layout. You can also use "AdaptiveGrid" which will flow in different directions depending on the window / device orientation.
Yes, layouts handle all of that. We have not coded in the type of "even driven" system you describe because it is not needed with the Fyne model. Everything is self-contained leading to simplicity and great re-usability. |
I think we should consider implementing something (or a helper around it) like the adaptive layouts that Gnome apps have. I'm a huge fan of how apps more or less become phone apps if they are small enough. However, I don't think the solution for that is having lifecycle APIs for everything. |
Yeah, the top level component of the window (if it's a custom widget or uses a custom layout) can react to size changes when its Resize function is called. I guess I can see why Andy was experimenting with extending containers, but it's so easy to write a custom widget extending BaseWidget and using NewSimpleRenderer with a container, that IMO we should just update docs to feature this more prominently/with more examples |
For sure. It's on my mind but I've still not found an API I like. There's the responsive layout in Fyne-x and a ticket here for "AppSkeleton" that may touch on this. #3044 |
@dweymouth it sounds easy, but I was never be able to do this I think fyne is fantastic. No other golang gui library remotely approaches the capabilities of fyne, and I do not want to give up learning it. However, I have been trying to use fyne for months, and I still cannot create a good mental model for it. I constantly hit "problems" where doing a very simple thing (like responding to an event) requires writting custom widgets and do other "magical" things that are not documented anywhere. :-( Here is an example question from 10 months ago that shows lack of documentation: https://stackoverflow.com/questions/78137067/fyne-custom-widget-not-refreshed There I was trying to create a custom widget and I failed, because I could not find documentation on how a WidgetRenderer works. The documentation here https://docs.fyne.io/extend/custom-widget is just an example, and does not explain many key concepts. After 10 months, I still don't know how to write a simple widget that can draw something on the screen. There are no simple examples anywhere on the internet for this (or at least I could not find it). After reading the related documentation, and reading through many articles, I still have a lot of questions just on this topic (custom rendering). Some weeks ago I tried to extend a widget and I ran into a segmentation fault: fyne-io/terminal#103 (comment) and I still wonder what is wrong. I just can't explain what is happening, the program panics at an unexpected place. Don't get me wrong, I'm not complaining. There are people who have written entire articles about "why fyne is bad". I am not one of them. I think a lot of work has gone into making fyne so versatile; and I think that if one has the time and skill, should spend energies on improving what has received for free, rather than criticizing. :-) I only give these examples because I don't know enough to tell what I don't understand. All I know is that "the picture doesn't add up", and when I try to make my own application I always fail, and when I ask others I get the answer "that's not how it should be done". I have used other GUI toolkits before (wx, gtk and many others). I have been building applications in the last 25 years, and somehow I just don't get it. Maybe the problem is with me, I'm getting old? :-) I think that I have a bad mental model of fyne, and I keep doing things "the wrong way". There seems to be a barrier that prevents me from using fyne efficiently. |
Well maybe, but all layouts built into fyne have a fixed structure. What I mean by fixed is that they lay out widgets that have been added to the layout. But it is not possible to change a layout from Grid to Stack when the aspect ratio of the window changes. In many cases, the structure of the layout needs to be changed when the window goes from landscape to portrait, or when it goes from a small window to a fullscreen window. The built-in layouts cannot be used for this. So this is another case where I don't know what is the right way to do it. Things that come into my mind:
|
There are examples everywhere and all through-out our code base and that of the many apps others have made https://apps.fyne.io/. Feel free to open specific questions or post issues, that way we can provide more specific help.
Thankfully that question was answered (though I don't think that you've accepted the answer). A custom widget should ExtendBaseWidget and when it wants to update the visuals of the items it uses to render it should update them accordingly. (as per docs In the Refresh() method it will update the graphical state based on any changes in the underlying widget.Button type. https://docs.fyne.io/extend/custom-widget)
That is a bug in the Terminal code and is being treated as such, the conversation over there seems to be heading to a solution that will work fine. I don't think it's fair to judge the toolkit API design by an external widget.
Ironically experience with other toolkits (depending on which ones) can hold things back when learning Fyne - it is different to some of them, which is why learning the design is important. You mostly talk about responding to "events" (which is quite understandable from a GTK+ background) but we don't have them in the same sense. Widgets that want to know about a user action implement the appropriate interface and they will be fed the info. This way fits much better with the Go type system and avoids a "AddEventHandler" and "RemoveEventHandler" for every possible event. In addition it allows platform-specific behaviour extensions without polluting the widget API. However the ticket topic seems to be about layout - which is quite separate from widgets. A widget fills the space given, it's that simple. To position them in different sizes or positions then update the parent layout or write a custom one as discussed above. |
I'm not judging. I think I just didn't understand something. Unfortunately, I can't tell you what I don't understand, it might be some general problem in my head. :-( |
Well, it just raised more questions, but I did not write more comments, because I realized that the problem is deeper. Probably with my mental model / thinking. |
It is absolutely possible to do that. The layout is set on a container - and the container will respect a new layout if you set a different algorithm into the container.
There is a document on this, https://docs.fyne.io/extend/custom-layout. If it helps you can consider
No, you should respond to the size of the container not the size of the window. |
If anything it seems like your mental model is of an immediate toolkit, where every draw is a complete refresh. We have a retained mode in which things are always visible and if you want something to look different you apply the change to those visible objects. |
My experience is that if I don't add a widget to any container, then it makes it invisible. I already wrote a program that hides a widget by removing it from the container. Is it a bad idea, or is it how I should do it? Is there a page that lists the possible interfaces (like Tappable) and their applications? I could find some pages for some interfaces, but I would like to know about all "event handling" interfaces. With event based widgets it is easy, I just look at the possible handlers in the source code. For the interface based approach, I cannot get this information from the source code. |
Apologies perhaps poor wording. Things are visible unless you
If looking at source code is your thing then the easiest way is: https://github.com/fyne-io/fyne/blob/master/canvasobject.go (for platform agnostic abstractions). There are more in the |
Thank you for your help and for youre time! I'll experiment more, possibly write my own layout before asking more question. |
I think we can probably close this issue, unless you think there is still a problem to be resolved with the docs or API? |
Checklist
Is your feature request related to a problem?
The
ShowAndRun
must be called from the main thread, and it blocks the main thread. I can start another go routine before callingShowAndRun
, and there I would like to wait until the main window appears. Why? Because I need to execute code that needs to know the size of the window, and also because it must be called with a running fyne event loop. But how? Only if I could create a custom main Window, I would be able to execute arbitrary code onShow()
.App.NewWindow
always returns afyne.Window
, it seems impossible to get notified when the main window is shown or hidden.I have tried this:
What happens is that it simply does not call
MainWindow.Show()
(tested on Linux).Interestingly, using callbacks in go is discouraged, but
fyne.Window
has some callback:SetOnDropped
,SetCloseIntercept
,SetOnClosed
. But there is noSetOnShow
, and (apparently) extending the window won't work. (Why? Is it a bug?)Is it possible to construct a solution with the existing API?
I think it is not possible to construct a direct solution with the existing API.
Describe the solution you'd like to see.
In the above example,
MainWindow
should be able to extend all of thefyne.Window
methods (SetTitle
,SetFullScreen
,Resize
,SetFixedSize
,CenterOnScreen
,SetPadded
,SetIcon
etc.) So the requested change is not an API change (or not necessarily). It is simply a request to make it possible to extendfyne.Window
.The text was updated successfully, but these errors were encountered: