COM->System.Windows.Forms
это не COM
.net Core, Visual Studio 2019, создаю проект в консоли(так ведь можно)
можно, но только когда вы знаете что делать дальше. а сейчас очевидно что не знаете:
— в .net Core формы поддерживатся с версии самой корки 3.*
— .net Core 3.* поддерживается начиная с Visual Studio 2019 (и то начиная со свежих билдов, осенних)
— визуального редактора форм на данный момент не существует
— есть руководство https://docs.microsoft.com/ru-ru/dotnet/core/porti… (что подключать там тоже написано)
совет — если вы только начинаете изучать программирование, не готовы осваивать XAML и нуждаете в визуальном редакторе форм, практикуйтесь сначала в .Net Framework, и используйте шаблон проекта WinForms
microsoft visual studio 2022
Проект Библиотека классов .NET 7
пкм по проекту (или зависимости) выбираем: Добавить => Ссылка на проект => Кликаем обзор =>
Отрывается окно => Переходим по структуре файлов вверх до папки «2022» =>
В поле поиска вставляем «System.Windows.Forms» => В результате ищем нужное (Примерно 3 снизу) =>
Выбираем => Тыкаем Добавить.
В свойствах проекта добавляем поддержку Windows Worms (если WPF).
Готово!
C:\Program Files\Microsoft Visual Studio\2022\Community\dotnet\runtime\shared\Microsoft.WindowsDesktop.App\6.0.14\System.Windows.Forms.dll
Вам нужно добавить ссылку на зависимость в свойствах проекта в обозревателе решений. Конечно, если проект не выполняется на .NET Core, в таком случае вам нужно подключить соответсвующее расширение с помощбю менеджера пакетов Nuget для проекта
Graphical User Interface (GUI) with Windows.Forms
Windows.Forms is the standard GUI toolkit for the .NET Framework. It is
also supported by Mono. Like every other thing in the world it has its
strong and weak points. Another GUI supported by .NET is Gtk#.
Which outguns which is up to you to judge. But before you can do that,
get a feel for Windows.Forms by going throught this tutorial.
Note 1: To compile programs using Windows.Forms you will need to
include -r:System.Windows.Forms
in the compile command. E.g. if
you save the examples in the file MyFirstForm.n, compile them with:
ncc MyFirstForm.n -r:System.Windows.Forms -o MyFirstForm.exe
Note 2: I am not going to go too much into details of every single
thing you can do with Windows.Forms. These can be pretty easily checked in the
Class reference.
I will just try to show you how to put all the bricks together.
Table of Contents
-
The first step
- Buttons, labels and the rest
- A simple menu
- Basic events
- Cleaning up
-
The second step
- Painting
- Overriding event handlers
- A simple animation with double-buffering
- Bitmaps and images
- Adding icons to the menu
The first step
using System.Drawing; using System.Windows.Forms; class MyFirstForm : Form { public static Main() : void { Application.Run(MyFirstForm()); } }
This is not too complex, is it? And it draws a pretty window on the
screen, so it is not utterly useless, either
Let us now try to customize the window a little. All the customization
should be placed in the class constructor.
using System.Drawing; using System.Windows.Forms; class MyFirstForm : Form { public this() { Text="My First Form"; //title bar ClientSize=Size(300,300); //size (without the title bar) in pixels StartPosition=FormStartPosition.CenterScreen; //I'm not telling FormBorderStyle=FormBorderStyle.FixedSingle; //not resizable } public static Main() : void { Application.Run(MyFirstForm()); } }
An empty Windows.Forms form.
Buttons, labels and the rest
Wonderful. Now the time has come to actually display something in our window. Let us add a slightly customized button. All you need to do is to add the following code to the constructor of your Form class (i.e. somewhere between public this() { and the first } after it).
def button=Button(); button.Text="I am a button"; button.Location=Point(50,50); button.BackColor=Color.Khaki; Controls.Add(button); def label=Label(); label.Text="I am a label"; label.Location=Point(200,200); label.BorderStyle=BorderStyle.Fixed3D; label.Cursor=Cursors.Hand; Controls.Add(label);
I hope it should pretty doable to guess what is which line responsible for. Perhaps you could only pay a little more attention to the last one. Buttons, labels, textboxes, panels and the like are all controls, and simply defining them is not enough, unless you want them to be invisible.
Also, the button we have added does actually nothing. But fear not, we shall discuss
a bit of events very soon.
A simple menu
Menus are not hard. Just take a look at the following example:
def mainMenu=MainMenu(); def mFile=mainMenu.MenuItems.Add("File"); def mFileDont=mFile.MenuItems.Add("Don't quit"); def mFileQuit=mFile.MenuItems.Add("Quit"); def mHelp=mainMenu.MenuItems.Add("Help"); def mHelpHelp=mHelp.MenuItems.Add("Help"); Menu=mainMenu;
It will create a menu with two drop-down submenus: File (with
options Don’t Quit and Quit) and Help with just
one option, Help.
A button, a label and a menu.
It is also pretty easy to add context menus to controls. Context menus are the ones which become visible when a control is right-clicked. First, you need to define the whole menu, and than add a reference to it to the button definition:
def buttonCM=ContextMenu(); def bCMWhatAmI=buttonCM.MenuItems.Add("What am I?"); def bCMWhyAmIHere=buttonCM.MenuItems.Add("Why am I here?"); ... def button=Button(); ... button.ContextMenu=buttonCM;
A context menu.
Basic events
Naturally, however nice it all might be, without being able to actually
serve some purpose, it is a bit pointless. Therefore, we will need to
learn handling events. There are in fact two ways to do it. Let us take
a look at the easier one for the begnning.
The first thing you will need to do is to add the System namespace:
You can skip this step but you will have to write
System.EventArgs and so on instead of EventArgs.
Then, you will need to add a reference to the event handler to your
controls. It is better to do it first as it is rather easy to forget
about it after having written a long and complex handler.
button.Click+=button_Click; ... mFileDont.Click+=mFileDont_Click; mFileQuit.Click+=mFileQuit_Click; ... mHelpHelp.Click+=mHelpHelp_Click;
Mind the += operator instead of = used when customizing
the controls.
Finally, you will need to write the handlers. Do not forget
to define the arguments they need, i.e. an object and an
EventArgs. Possibly, you will actually not use them but you have
to define them anyway. You can prefix their names with a _ to avoid
warnings at compile time.
private button_Click(_sender:object, _ea:EventArgs):void{ Console.WriteLine("I was clicked. - Your Button"); } private mFileQuit_Click(_sender:object, _ea:EventArgs):void{ Application.Exit(); }
This is the way you will generally want to do it. But in this very case
the handlers are very short, and like all handlers, are not very often
used for anything else than handling events. If so, we could rewrite them
as lambda expressions which will save a good bit of space and clarity.
button.Click+=fun(_sender:object, _ea:EventArgs){ Console.WriteLine("I wrote it. - button_Click as a lambda"); }; mFileQuit.Click+=fun(_sender:object, _ea:EventArgs){ Application.Exit(); };
Cleaning up
After you are done with the whole application, you should clean
everything up. In theory, the system would do it automatically anyway
but it certainly is not a bad idea to help the system a bit. Especially
that it is not a hard thing to do at all, and only consists of two steps.
The first step is to add a reference to System.ComponentModel
and define a global variable of type Container:
using System.ComponentModel; ... class MyFirstForm : Form { components : Container = null; ...
In the second and last step, you will need to override the Dispose
method. It could even fit in one line if you really wanted it to.
protected override Dispose(disposing : bool) : void { when (disposing) when (components!=null) components.Dispose(); base.Dispose(d); }
The second step
You should now have a basic idea as to what a form looks like. The time
has come to do some graphics.
Painting
There is a special event used for painting. It is called Paint and you
will need to create a handler for it.
using System; using System.Drawing; using System.Windows.Forms; class MySecondForm : Form { public this() { Text="My Second Form"; ClientSize=Size(300,300); Paint+=PaintEventHandler(painter); } private painter(_sender:object, pea:PaintEventArgs):void{ def graphics=pea.Graphics; def penBlack=Pen(Color.Black); graphics.DrawLine(penBlack, 0, 0 , 150, 150); graphics.DrawLine(penBlack, 150, 150, 300, 0); } public static Main():void{ Application.Run(MySecondForm()); } }
A reference to the painter method should be added in the form class
constructor (it affects the whole window), but this time it is a
PaintEventHandler. Same as PaintEventArgs in the handler
itself. In the handler, you should first define a variable of type
PaintEventArgs.Graphics. This is the whole window. This is where you will
be drawing lines, circles, strings, images and the like (but not pixels;
we will discuss bitmaps later on). To draw all those things you will
need pens and brushes. In our example we used the same pen twice. But
sometimes you will only need it once. In such case, there is no point
in defining a separate variable for it. Take a look at the next example.
Painting in Windows.Forms.
Overriding event handlers
Another way to define a handler is to override the default one provided
by the framework. It is not at all complicated, it is not dangerous and
in many cases it will prove much more useful. Take a look at the example
overriding the OnPaint event handler:
protected override OnPaint(pea:PaintEventArgs):void{ def g=pea.Graphics; g.DrawLine(Pen(Color.Black), 50, 50, 150, 150); }
Naturally, when you override the handler, there is no need any longer
to add a reference to it in the class constructor.
By the same token can you override other events. One of the possible
uses is to define quite complex clickable areas pretty easily:
protected override OnPaint(pea:PaintEventArgs):void{ def g=pea.Graphics; for (mutable x=0; x<300; x+=10) g.DrawLine(Pen(Color.Blue), x, 0, x, 300); } protected override OnMouseDown(mea:MouseEventArgs):void{ when (mea.X%10<4 && mea.Button==MouseButtons.Left) if (mea.X%10==0) Console.WriteLine("You left-clicked a line.") else Console.WriteLine($"You almost left-clicked a line ($(mea.X%10) pixels)."); }
Easily creating a complex clickable image map.
A simple animation with double-buffering
What is an animation without double-buffering? Usually, a flickering
animation. We do not want that. Luckily enough, double-buffering is as
easy as abc in Windows.Forms.
In fact, all you need to do is to set three style flags and override the
OnPaint event handler instead of writing your own handler and assigning
it to the event.
class Animation:Form{ mutable mouseLocation:Point; //the location of the cursor public this(){ Text="A simple animation"; ClientSize=Size(300,300); SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true); //double-buffering on } protected override OnPaint(pea:PaintEventArgs):void{ def g=pea.Graphics; g.FillRectangle(SolidBrush(Color.DimGray),0,0,300,300); //clearing the window def penRed=Pen(Color.Red); g.FillEllipse(SolidBrush(Color.LightGray), mouseLocation.X-15, mouseLocation.Y-15, 29, 29); g.DrawEllipse(penRed, mouseLocation.X-15, mouseLocation.Y-15, 30, 30); g.DrawLine(penRed, mouseLocation.X, mouseLocation.Y-20, mouseLocation.X, mouseLocation.Y+20); g.DrawLine(penRed, mouseLocation.X-20, mouseLocation.Y, mouseLocation.X+20, mouseLocation.Y); } protected override OnMouseMove(mea:MouseEventArgs):void{ mouseLocation=Point(mea.X,mea.Y); Invalidate(); //redraw the screen every time the mouse moves } public static Main():void{ Application.Run(Animation()); } }
As you can see, the basic structure of a window with animation is
pretty easy. Main starts the whole thing as customized in the
constructor. The OnPaint event handler is called immediately. And
then the whole thing freezes waiting for you to move the mouse. When
you do, the OnMouseMove event handler is called. It checks the
new position of the mouse, stores it in mouseLocation and tells
the window to redraw (Invalidate();).
Try turning double-buffering off (i.e. comment the SetStyle…
line) and moving the mouse slowly. You will see the viewfinder
flicker. Now turn double-buffering back on and try again. See the
difference?
Well, in this example you have to move the mouse slowly to actually
see any difference because the viewfinder we are drawing is a pretty
easy thing to draw. But you can be sure that whenever anything more
complex comes into play, the difference is very well visible without
any extra effort.
A simple animation with double-buffering.
Bitmaps and images
I promised I would tell you how to draw a single pixel. Well, here we are.
protected override OnPaint(pea:PaintEventArgs):void{ def g=pea.Graphics; def bmp=Bitmap(256,1); //one pixel height is enough; we can draw it many times for (mutable i=0; i<256; ++i) bmp.SetPixel(i, 0, Color.FromArgb(i,0,i,0)); for (mutable y=10; y<20; ++y) g.DrawImage(bmp, 0, y); }
So, what do we do here? We define a bitmap of size 256,1. We draw onto
it 256 pixels in colours defined by four numbers: alpha (transparency),
red, green, and blue. But as we are only manipulating alpha and green,
we will get a nicely shaded green line. Finally, we draw the bitmap onto
the window ten times, one below another.
Mind the last step, it is very important. The bitmap we had defined is
an offset one. Drawing onto it does not affect the screen in any way.
Now, that you know the DrawImage method nothing can stop you from
filling your window with all the graphic files you might be having on
your disk, and modifying them according to your needs.
class ImageWithAFilter:Form{ img:Image=Image.FromFile("/home/johnny/pics/doggy.png"); //load an image bmp:Bitmap=Bitmap(img); //create a bitmap from the image public this(){ ClientSize=Size(bmp.Width*2, bmp.Height); } protected override OnPaint(pea:PaintEventArgs):void{ def g=pea.Graphics; for (mutable x=0; x<bmp.Width; ++x) for (mutable y=0; y<bmp.Height; ++y) when (bmp.GetPixel(x,y).R>0){ def g=bmp.GetPixel(x,y).G; def b=bmp.GetPixel(x,y).B; bmp.SetPixel(x,y,Color.FromArgb(255,0,g,b)); } g.DrawImage(img,0,0); //draw the original image on the left g.DrawImage(bmp,img.Width,0); //draw the modified image on the right } ... }
This example draws two pictures: the original one on the left and the
modified one on the right. The modification is a very simple filter
entirely removing the red colour.
A simple graphic filter.
Adding icons to the menu
Adding icons is unfortunately a little bit more complicated than other
things in Windows.Forms.
You will need to provide handlers for two events: MeasureItem
and DrawItem, reference them in the right place, and set the menu
item properly.
mFileQuit.Click+=EventHandler( fun(_) {Application.Exit();} ); mFileQuit.OwnerDraw=true; mFileQuit.MeasureItem+=MeasureItemEventHandler(measureItem); mFileQuit.DrawItem+=DrawItemEventHandler(drawItem);
private measureItem(sender:object, miea:MeasureItemEventArgs):void{ def menuItem=sender:>MenuItem; def font=Font("FreeMono",8); //the name and the size of the font miea.ItemHeight=(miea.Graphics.MeasureString(menuItem.Text,font).Height+5):>int; miea.ItemWidth=(miea.Graphics.MeasureString(menuItem.Text,font).Width+30):>int; } private drawItem(sender:object, diea:DrawItemEventArgs):void{ def menuItem=sender:>MenuItem; def g=diea.Graphics; diea.DrawBackground(); g.DrawImage(anImageDefinedEarlier, diea.Bounds.Left+3, diea.Bounds.Top+3, 20, 15); g.DrawString(menuItem.Text, diea.Font, SolidBrush(diea.ForeColor), diea.Bounds.Left+25, diea.Bounds.Top+3); }
A menu with an icon.
From Wikibooks, open books for an open world
To create a Windows desktop application we use the library represented by System.Windows.Forms
namespace. Some commonly used classes in this namespace include:
- Control — generic class from which other useful classes, like
Form
,TextBox
and others listed below are derived - Form — this is the base class for the program window. All other controls are placed directly onto a
Form
or indirectly on another container (likeTabPage
orTabControl
) that ultimately resides on theForm
. When automatically created in Visual Studio, it is usually subclassed asForm1
. - Button — a clickable button
- TextBox — a singleline or multiline textbox that can be used for displaying or inputting text
- RichTextBox — an extended
TextBox
that can display styled text, e.g. with parts of the text colored or with a specified font. RichTextBox can also display generalized RTF document, including embedded images. - Label — simple control allowing display of a single line of unstyled text, often used for various captions and titles
- ListBox — control displaying multiple items (lines of text) with ability to select an item and to scroll through it
- ComboBox — similar to
ListBox
, but resembling a dropdown menu - TabControl and TabPage — used to group controls in a tabbed interface (much like tabbed interface in Visual Studio or Mozilla Firefox). A
TabControl
contains a collection ofTabPage
objects. - DataGrid — data grid/table view
The Form
class (System.Windows.Forms.Form) is a particularly important part of that namespace because the form is the key graphical building block of Windows applications. It provides the visual frame that holds buttons, menus, icons, and title bars together. Integrated development environments (IDEs) like Visual C# and SharpDevelop can help create graphical applications, but it is important to know how to do so manually:
using System.Windows.Forms; public class ExampleForm : Form // inherits from System.Windows.Forms.Form { public static void Main() { ExampleForm wikibooksForm = new ExampleForm(); wikibooksForm.Text = "I Love Wikibooks"; // specify title of the form wikibooksForm.Width = 400; // width of the window in pixels wikibooksForm.Height = 300; // height in pixels Application.Run(wikibooksForm); // display the form } }
The example above creates a simple Window with the text «I Love Wikibooks» in the title bar. Custom form classes like the example above inherit from the System.Windows.Forms.Form
class. Setting any of the properties Text
, Width
, and Height
is optional. Your program will compile and run successfully, if you comment these lines out, but they allow us to add extra control to our form.
|
This section is a stub. You can help Wikibooks by expanding it. |
An event is an action being taken by the program when a user or the computer makes an action (for example, a button is clicked, a mouse rolls over an image, etc.). An event handler is an object that determines what action should be taken when an event is triggered.
using System.Windows.Forms; using System.Drawing; public class ExampleForm : Form // inherits from System.Windows.Forms.Form { public ExampleForm() { this.Text = "I Love Wikibooks"; // specify title of the form this.Width = 300; // width of the window in pixels this.Height = 300; // height in pixels Button HelloButton = new Button(); HelloButton.Location = new Point(20, 20); // the location of button in pixels HelloButton.Size = new Size(100, 30); // the size of button in pixels HelloButton.Text = "Click me!"; // the text of button // When clicking the button, this event fires HelloButton.Click += new System.EventHandler(WhenHelloButtonClick); this.Controls.Add(HelloButton); } void WhenHelloButtonClick(object sender, System.EventArgs e) { MessageBox.Show("You clicked! Press OK to exit this message"); } public static void Main() { Application.Run(new ExampleForm()); // display the form } }
|
This section is a stub. You can help Wikibooks by expanding it. |
The Windows Forms namespace has a lot of very interesting classes. One of the simplest and important is the Form
class. A form is the key building block of any Windows application. It provides the visual frame that holds buttons, menus, icons and title bars together. Forms can be modal and modalless, owners and owned, parents and children. While forms could be created with a notepad, using a form editor like VS.NET, C# Builder or Sharp Develop makes development much faster. In this lesson, we will not be using an IDE. Instead, save the code below into a text file and compile with command line compiler.
using System.Windows.Forms; using System.Drawing; public class ExampleForm : Form // inherits from System.Windows.Forms.Form { public ExampleForm() { this.Text = "I Love Wikibooks"; // specify title of the form this.BackColor = Color.White; this.Width = 300; // width of the window in pixels this.Height = 300; // height in pixels // A Label Label TextLabel = new Label(); TextLabel.Text = "One Label here!"; TextLabel.Location = new Point(20, 20); TextLabel.Size = new Size(150, 30); TextLabel.Font = new Font("Arial", 12); // See! we can modify the font of text this.Controls.Add(TextLabel); // adding the control to the form // A input text field TextBox Box = new TextBox(); // inherits from Control Box.Location = new Point(20, 60); // then, it have Size and Location properties Box.Size = new Size(100, 30); this.Controls.Add(Box); // all class that inherit from Control can be added in a form } public static void Main() { Application.EnableVisualStyles(); Application.Run(new ExampleForm()); // display the form } }
Чем асинхронная логика (схемотехника) лучше тактируемой, как я думаю, что помимо энергоэффективности — ещё и безопасность.
Hrethgir 14.05.2025
Помимо огромного плюса в энергоэффективности, асинхронная логика — тотальный контроль над каждым совершённым тактом, а значит — безусловная безопасность, где безконтрольно не совершится ни одного. . .
Многопоточные приложения на C++
bytestream 14.05.2025
C++ всегда был языком, тесно работающим с железом, и потому особеннно эффективным для многопоточного программирования. Стандарт C++11 произвёл революцию, добавив в язык нативную поддержку потоков,. . .
Stack, Queue и Hashtable в C#
UnmanagedCoder 14.05.2025
Каждый опытный разработчик наверняка сталкивался с ситуацией, когда невинный на первый взгляд List<T> превращался в узкое горлышко всего приложения. Причина проста: универсальность – это прекрасно,. . .
Как использовать OAuth2 со Spring Security в Java
Javaican 14.05.2025
Протокол OAuth2 часто путают с механизмами аутентификации, хотя по сути это протокол авторизации. Представьте, что вместо передачи ключей от всего дома вашему другу, который пришёл полить цветы, вы. . .
Анализ текста на Python с NLTK и Spacy
AI_Generated 14.05.2025
NLTK, старожил в мире обработки естественного языка на Python, содержит богатейшую коллекцию алгоритмов и готовых моделей. Эта библиотека отлично подходит для образовательных целей и. . .
Реализация DI в PHP
Jason-Webb 13.05.2025
Когда я начинал писать свой первый крупный PHP-проект, моя архитектура напоминала запутаный клубок спагетти. Классы создавали другие классы внутри себя, зависимости жостко прописывались в коде, а о. . .
Обработка изображений в реальном времени на C# с OpenCV
stackOverflow 13.05.2025
Объединение библиотеки компьютерного зрения OpenCV с современным языком программирования C# создаёт симбиоз, который открывает доступ к впечатляющему набору возможностей. Ключевое преимущество этого. . .
POCO, ACE, Loki и другие продвинутые C++ библиотеки
NullReferenced 13.05.2025
В C++ разработки существует такое обилие библиотек, что порой кажется, будто ты заблудился в дремучем лесу. И среди этого многообразия POCO (Portable Components) – как маяк для тех, кто ищет. . .
Паттерны проектирования GoF на C#
UnmanagedCoder 13.05.2025
Вы наверняка сталкивались с ситуациями, когда код разрастается до неприличных размеров, а его поддержка становится настоящим испытанием. Именно в такие моменты на помощь приходят паттерны Gang of. . .
Создаем CLI приложение на Python с Prompt Toolkit
py-thonny 13.05.2025
Современные командные интерфейсы давно перестали быть черно-белыми текстовыми программами, которые многие помнят по старым операционным системам. CLI сегодня – это мощные, интуитивные и даже. . .