Open Maobuff opened 5 years ago
Hello! Today later I will create a complete example for ComboBox and MenuItem with styles and others, and you can see it on github. But below I have attached a simple example (including image binding). combobox_example.txt
Update: SpaceVIl has some annoying bugs with ComboBox, and today later a new version of SpaceVIL will be available without these bugs.
Also how do I change font for each item in combobox? Do i have to change it in MenuItem? If yes then maybe add feature to set font for all of comboboxs items, like you have with alignment in stacks (both horisontal and vertical)
If you need to change the font for MenuItem there are a several ways to do this:
Create static method:
static MenuItem GetMyMenuItem(String text)
{
MenuItem mi = New MenuItem(text);
mi.SetFont(new Font(new FontFamily("Arial"), 16, FontStyle.Regular));
return mi;
}
Create a style for MenuItem like this:
Style style = Style.GetMenuItemStyle();
style.Font = new Font(new FontFamily("Arial"), 16, FontStyle.Regular);
return style;
and apply style after creating MenuItem:
MenuItem mi = new MenuItem("My MenuItem");
mi.SetStyle(style);
or
MenuItem mi1 = new MenuItem("My MenuItem1");
MenuItem mi2 = new MenuItem("My MenuItem2");
MenuItem mi3 = new MenuItem("My MenuItem3");
style.SetStyle(m1, mi2, mi3);
Create a style for MenuItem and replace the default theme style. In this case, all new instances of MenuItem will automatically apply the new style (the best way to replace default style is to replace it before creating any window, for example in the Main function):
static void Main(string[] args)
{
SpaceVIL.Common.CommonService.InitSpaceVILComponents();
// create new style (this can be done through a static "getStyle-function")
Style style = Style.GetMenuItemStyle();
style.Font = new Font(new FontFamily("Arial"), 16, FontStyle.Regular);
// replace default style
DefaultsService.GetDefaultTheme().ReplaceDefaultItemStyle(typeof(SpaceVIL.MenuItem), style);
// create and show window
MainWindow mw = new MainWindow();
mw.Show();
}
Create a new class that extends MenuItem and set the desired font in its constructor:
public class MyMenuItem : SpaceVIL.MenuItem
{
public MyMenuItem()
{
SetFont(new Font(new FontFamily("Arial"), 16, FontStyle.Regular));
}
}
and use MyMenuItem instead of base MenuItem:
MyMenuItem mymi = new MyMenuItem();
ComboBox combo = new ComboBox(mymi);
PS: New version (v0.3.4.2) of SpaceVIL avaliable. Also on github I added Tutorials/ComboBoxExample which may be interesting for you.
Well, what about adding image to ComboBox itself, not a MenuItem? TextMargin makes ComboBox smaller instead of shifting Text. And what about VerticalStack SetContentAlignment method, for example, I need to have 4 elements (3 ComboBoxes and one Label in my case) on with this alignment : two of them alight to left and other two to the right. Things i tried: (1)Making VerticalStack SetContentAlignment Left, then manually changing two elements that need alignment to the right. Result invisible elements than go with right alignment
(2)Making VerticalStack SetContentAlignment Right, then manually changing two elements that need alignment to the left. The order of the elements is inverted (first added element closer to left side, well it doesn't matter) and ComboBox which alignment was set to left is invisile
(3)Setting manually Left and Right of each element resulted in invisible ComboBoxes
Adding an image to ComboBox: The approach is the same - just add ImageItem to ComboBox (in Tutorials/ComboBoxExample I added an ellipse into ComboBox)
ComboBox combo = new ComboBox(menu_item1, menu_item2);
AddItem(combo);
ImageItem img = new ImageItem(<Bitmap>); //here you must provide Bitmap
... set img properties like size, aspect ratio, etc....
combo.AddItem(img);
or create your own modified ComboBox:
public class MyComboBox : SpaceVIL.ComboBox
{
ImageItem img = null;
public MyComboBox (Bitmap image, params MenuItem[] items) : base(items)
{
img = new ImageItem(image);
SetTextMargin(30, 0, 0, 0);
}
public override void InitElements()
{
base.InitElements(); //required
// img attr
img.SetSizePolicy(SizePolicy.Fixed, SizePolicy.Fixed);
img.SetSize(20, 20);
img.SetAlignment(ItemAlignment.Left, ItemAlignment.VCenter);
img.SetMargin(15, 0, 0, 0);
img.KeepAspectRatio(true);
// add image
AddItem(img);
}
}
and use MyComboBox as a ComboBox:
MyComboBox mcb = new MyComboBox(bitmap, menu_item1, menu_item2);
VerticalStack (do you mean HorizontalStack?), 4 elements with alignment : two of them alight to left and other two to the right. Stack items were not meant to work like this. If you want to achieve such alignment you should use Frame with 2 HorizontalStack: the second one should SetContenAlignment to ItemAlignment.Right:
// prepare layout
Frame frame = new Frame();
SetHeightPolicy(SizePolicy.Fixed);
SetHeight(40); // or any other value
HorizontalStack hsLeft = new HorizontalStack();
HorizontalStack hsRight = new HorizontalStack();
hsRight.SetContentAlignment(ItemAlignment.Right);
AddItem(frame); // add to window
frame.AddItems(hsLeft, hsRight);
// prepare content Label label = new Label("Name"); ...set label attr (size, font and etc)...
ComboBox cb1 = new ComboBox(); ...set cb1 attr (size and etc)... ComboBox cb2 = new ComboBox(); ...set cb2 attr (size and etc)... ComboBox cb3 = new ComboBox(); ...set cb3 attr (size and etc)...
// add content hsLeft.AddItems(label, cb1); hsLeft.AddItems(cb2, cb3);
or you can simply manually set a proper attributes to each item:
// prepare layout Frame frame = new Frame(); SetHeightPolicy(SizePolicy.Fixed); SetHeight(40); // or any other value AddItem(frame); // add to window
// prepare content Label label = new Label("Name"); ...set label attr (size, font and etc)...
ComboBox cb1 = new ComboBox(); cb1.SetMargin(label.getWidth() + 5, 0, 0, 0); ...AND SET OTHER cb1 attr (size and etc)...
ComboBox cb2 = new ComboBox(); cb2.SetAlignment(ItemAlignment.Right); ...AND SET OTHER cb2 attr (size and etc)...
ComboBox cb3 = new ComboBox(); cb3.SetAlignment(ItemAlignment.Right); cb3.SetMargin(0, 0, cb2.getWidth() + 5, 0); ...AND SET OTHER cb3 attr (size and etc)...
// add comtent frame.AddItems(label, cb1, cb2, cb3);
or the simplest way - just add Frame between second and third element. Frame will expand them:
// prepare layout HorizontalStack hStack = new HorizontalStack(); ... set hStack attr (size and etc)... Frame frame = new Frame();
// prepare content Label label = new Label("Name"); ...set label attr (size, font and etc)... ComboBox cb1 = new ComboBox(); ...set cb1 attr (size and etc)... ComboBox cb2 = new ComboBox(); ...set cb2 attr (size and etc)... ComboBox cb3 = new ComboBox(); ...set cb3 attr (size and etc)...
// add content AddItem(hStack); hStack.AddItem(label, cb1, frame, cb2, cb3);
PS: I found a new bug in ComboBox so... a new version (v0.3.4.21) of SpaceVIL availiable (required if you want to use "MyComboBox" example).
Update: I added a new solution for your alignment problem in my previous comment.
I managed to put all items as I wanted. But SetTextMargin on ComboBox makes is field smaller like shown in attached image. Yes in theory I can put Image on the right side of ComboBox by shifting it from center, but in design perspective I want it to be at left side. Here what I did:
_status = new ComboBox(_statusAll, _statusDone, _statusWIP); _status.SetWidth(125); _status.SetFontSize(25); _status.SetWidthPolicy(SizePolicy.Fixed); _status.SetTextMargin(new Indents(30, 0, 0, 0)); ImageItem img = new ImageItem(Resources.Done); img.SetSizePolicy(SizePolicy.Fixed, SizePolicy.Fixed); img.SetSize(20, 20); img.SetAlignment(ItemAlignment.Left, ItemAlignment.VCenter); img.KeepAspectRatio(true); ................ _hs.AddItem(_status); ................ _status.AddItem(img);
What version of SpaceVIL do you use?
_status.SetTextMargin(new Indents(30, 0, 0, 0))
is was one of the bugs that I fixed in the new version 0.3.4.21. If you do not want to use the new version, than in your case you should create a style for ComboBox:
Style style = Style.GetComboBoxStyle();
style.SetSize(125, 25);
style.Font = DefaultsService.GetDefaultFont(25);
style.WidthPolicy = SizePolicy.Fixed;
Style selectionStyle = style.GetInnerStyle("selection");
if (selectionStyle != null)
selectionStyle.SetPadding(30, 0, 0, 0);
// apply style
_status = new ComboBox(_statusAll, _statusDone, _statusWIP);
_status.SetStyle(style);
//your image
ImageItem img = new ImageItem(Resources.Done);
img.SetSizePolicy(SizePolicy.Fixed, SizePolicy.Fixed);
img.SetSize(20, 20);
img.SetAlignment(ItemAlignment.Left, ItemAlignment.VCenter);
img.KeepAspectRatio(true);
**img.SetMargin(5, 0, 0, 0);** // do not forget to indent for beauty
I think I switched to v0.3.4.2 as soon as I saw you publish new release. Updated to latest version(0.3.4.21) and bug is fixed
If you have any other questions regarding SpaceVIL framework, feel free to ask me.
What about load time? In my project I have about 400 Items in total (~325 of frames/horizontalstack etc.. and about 75 pictures). Project starting is around 10 seconds. All pictures are located in resource file.
Hmm... In my cases, loading times were always acceptable. For example, the load time of SimpleImageViewer with 100 images of 64x64 pixels (stored on the HDD) is about one second. The load time of CharacterEditor with 1000 generated characters (each character with image of 32x32 pixels) is also about one second (total items: 9078). If you want to know the total number of items:
Console.WriteLine(ItemsLayoutBox.GetLayoutItems(myWindow.GetWindowGuid()).Count);
Place it inside at the end of InitWindow() function.
In my tests only a few cases caused a significant increase in load time:
What is size of your images? What is the actual number of items in your project?
PS. SimpleImageViewer and CharacterEditor are examples of using SpaceVIL and can be found in the current github repository.
Console.WriteLine(ItemsLayoutBox.GetLayoutItems(myWindow.GetWindowGuid()).Count);
outputs 694
I have set of images (about 10 uniques), each is about 512x512. But all of them are located in resource file, decoded to ready to use bitmap.
Update: In my case I have Container (HorizontalStack) where I put 14 objects (half of them are simple spacers), 3 of them are icons. I measured time that takes for each of them to load: ~250ms in total and about 70-90ms for each picture(from creating a variable to finish setting up all of its properties), less than 0 for AddItems().
Update 2: Going to change resolution of icons to somethings 32x32 or 20x20
What are CPU do you have? My CPU: Intel I5-6300U I tried to load 80 images (512x512) form my hdd and it takes 12 ms.
AMD Ryzen 7 3700x. Reducing resolution helps in load time.
Wow. It is very good CPU, but for now, your load time is a mystery for me. Can your antivirus slow down the application loading?
I dont have any, only Windows Defender. Update: disabling in make zero difference. Update 2: reducing resolution twice increased total load time for each element to about 50ms Update 3: putting application to an ssd reduced time to about 20-25ms
After little bit of testing i figgured out that new ImageItem(Resources.Test);
takes 99.99% of measured time. Also noticed that one of my cores is loaded to a full 100% for load time, and I reach average boost clocks (All I wanted to say that this is not a CPU related problem like "Thermal malware detection" or other). What is your method of loading Images? Do you load them by reading file or using resource?
Hmm... Ok, I will try to find out in which cases images in resource files can increase load time.
Update: I also noted that you are using glfw, How are you loading textures from images? Are you using bitmap.LockBits to load textures?
I load images directly from hdd.
Inside new ImageItem(Resources.Test);
image converted to a byte array.
No I am not using bitmap.LockBits, just conversion to a byte array.
Are you using bitmap.GetPixel ? Had performance issues with GetPixel method in past.
Yes. If you want, I could create a test version of SpaceVIL later today that uses bitmap.LockBits, and you can test it. Are you ok with that?
Sure!
Also I updated System.Drawing.Common and get around 13ms for each picture (from hdd). Still not happy with the result.
Update: Measured load time of SetIcon(Resources.Icon, Resources.Icon);
. Result is 250ms.
I also find old project with glfw on c# an tried to load texture using GetPixel method. result is 2 full seconds for loading texture(1024x1024) from file. Switched to LockBits method and time is reduce to few ms.
Good. Can you provide example of using LockBits?
Sure! Texture.zip
Ok, I did it. Try this version (paste it in address line to download): https://spvessel.com/spacevil/downloads/maobuff/spacevil_dotnet_core.zip Make sure that the framework version is 0.3.4.22 Update: this version has not yet been tested for memory leaks, keep this in mind.
Loading for first container is 23ms, for next ones less than 1ms (25 copies of HorizontalStack with 14 total elements, 3 of which are pictures). For testing I used same texture for all of pictures (512x512). SetIcon() have same load time of ~240ms (512x512). Loading for other texture is ~2ms (512x512).
I can call it a success, but take a look at SetIcon() method. Maybe its still using GetPixel method.
Yes. I implemented your method only for ImageItem
. When I fully test it, I will replace all places where GetPixel
is used.
And thanks for finding this bug.
Hello, im looking for exaple how to use ComboBox in C#, and also is is possible to bind image to a MenuItem?