I am trying to create a generous and quick to create components in a GUI, the code that I did was the following, but I know he does not do what I want, and I also do not know how I can do.
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
public ref class GUI : public Form
{
private:
int x, y;
String^ text;
Button^ btm;
public:
GUI(int _x, int _y, String^ caption)
{
x = _x;
y = _y;
text = caption;
init_btm();
}
void init_btm()
{
btm = gcnew Button();
btm->Location = Point(x, y);
btm->Text = text;
Controls->Add(btm);
}
};
int main(array<System::String ^> ^args)
{
Application::Run(gcnew GUI(20,20,"Ola mundo"));
return 0;
}
I'm trying to create something like this...
rather, a dynamic way to create components and add components to the form
well, what I would do is create a class where I can access it, and create multiple buttons, and this class, add these buttons on Form maybe something like this:
ADD_BTM^ btm;
btm->Add(20,20,"Hello 1");
btm->Add(20,20,"Hello 2");
You also may be wondering, why I did not "design" my interface, I am studying C++/CLI, and I'm trying to create this program, just to study.
I appreciate the help.
You already know how to add new button to the form, you just need to add parameters to the method and then call it repeatedly:
In public section of GUI:
void AddButton(int x, int y, String^ caption)
{
auto button = gcnew Button();
button->Location = Point(x, y);
button->Text = caption;
Controls->Add(button);
}
In main:
auto form = gcnew GUI();
form->AddButton(20, 20, "Hello 1");
form->AddButton(40, 40, "Hello 2");
Application::Run(form);
(The code uses auto from C++11. If you don't use VS 2010, just replace them with the actual type.)
Related
The code is taken from here:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.timer?view=windowsdesktop-6.0
private:
static System::Windows::Forms::Timer^ myTimer = gcnew System::Windows::Forms::Timer;
static int alarmCounter = 1;
static bool exitFlag = false;
// This is the method to run when the timer is raised.
static void TimerEventProcessor( Object^ /*myObject*/, EventArgs^ /*myEventArgs*/ )
{
myTimer->Stop();
// Displays a message box asking whether to continue running the timer.
if ( MessageBox::Show( "Continue running?", String::Format( "Count is: {0}", alarmCounter ), MessageBoxButtons::YesNo ) == DialogResult::Yes )
{
// Restarts the timer and increments the counter.
alarmCounter += 1;
myTimer->Enabled = true;
}
else
{
// Stops the timer.
exitFlag = true;
}
}
For example, after the line myTimer->Stop(); I want to use my own method. How do I identify it? E0020 ID "draw 1" is not defined.
System:: Void Practform::MyForm::draw1() {
. . .
}
Please tell me, because I'm a little stalled, since I've never worked with this.
I have a feeling that what you are bumping up against is attempting to invoke an instance method from a static method. To do so, you would need to have an instance of the class which has the method, e.g:
ref struct Foo {
void InstanceMethod() {}
static void StaticMethod() {
auto instance = gcnew Foo();
instance->InstanceMethod();
}
}
called like so:
Foo::StaticMethod();
However, taking the example code, it could be easier (and more appropriate) to change the static methods to instance methods, like so:
using namespace System;
using namespace System::Windows::Forms;
ref struct MyForm : Form {
Timer ^myTimer = gcnew Timer();
MyForm(void) {
myTimer->Tick += gcnew EventHandler(this, &MyForm::TimerEventProcessor);
myTimer->Interval = 5000;
myTimer->Start();
}
void TimerEventProcessor(Object ^, EventArgs ^) {
myTimer->Stop();
draw1();
}
void draw1() {
MessageBox::Show("Done", "Timer is done", MessageBoxButtons::OK);
}
};
called like so:
auto form = gcnew MyForm();
form->Show();
Notes:
I'm assuming that you've added the code from the example into your own class, called MyForm
I've used struct throughout instead of class to make everything public - you should use the appropriate access modifiers to your use case
The most notable change is the use of the EventHandler constructor which takes an instance of the handler as its first argument, and the method to execute as its second.
The advantages of using instance methods and properties are that:
you will have access to this in the draw1() method (given the name of the method, is likely to want to draw using the form instance), and
the Timer instance will be garbage collected as appropriate,
i have a program like this
let form = new Form()
let drawArea = new Panel(Location = new Point(200,0), Height = 600, Width = 800)
let rectBrush = new SolidBrush(Color.Blue)
form.Controls.Add(drawArea)
drawArea.MouseClick.Add(fun args ->
drawArea.Paint.Add(fun e ->
e.Graphics.FillRectangle(rectBrush, args.X, args.Y, 50, 50)))
Application.Run(form)
so when i click a blue rectangle appears. However, where are these rectangles stored? is there any way to retrive a list of all the rectangles being part of the "drawArea"?
Otherwise, is there a way to add rectangles as child controllers to a panel or simular winform object?
Thank you
I don't know of a way to retrieve these rectangles that way.
The best you can do is make a Rectangle class, and make it inherit from Control or UserControl. Then override it's protected OnPaint(...) method. For example:
public class FilledRectangle : UserControl
{
private readonly float x, y, w, h;
// also the brush here
public FilledRectangle(float x, float y, float w, float h)
{
this.x = x;
// ...
}
protected override void OnPaint(PaintEventArgs e) // not sure about the event args type name
{
e.Graphics.FillRectangle(this.myBrush, this.x, this.y, this.w, this.h);
}
}
Now you can simple add an object of this type to the Controls collection like so:
Controls.Add(new FilledRectangle(...));
With this approach you can easily create a collection of the rectangle objects and make them behave like you want them to.
Note that the examples I wrote above are in C#, but it shouldn't be too difficult to port it to F#. Only reason I'm not doing it is because I'm not very familiar with its syntax. Your question is not F#-specific, but .NET-specific.
Also note that as it has been commented by Hans, the Paint event won't fire until you call Invalidate().
In Win32 API, function SetWindowPos provided an easy way to move and resize window at once.
However, in WPF class Window doesn't have a method like SetWindowPos. So I must code like the following:
this.Left += e.HorizontalChange;
this.Top += e.VerticalChange;
this.Width = newWidth;
this.Height = newHeight;
Of course, it works well, but it's not simple. And it looks dirty.
How can i move a window and resize at once?
Is there an API?
I know you've already solved your problem, but I'll post a solution that I found in case it helps others.
Basically, You must declare that SetWindowsPos as an imported function from Win32 this is the signature
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
The function needs the hWnd of your window, in order to get it you can add an handler on the initialization of your windows (for example you could listen for the "SourceInitialized" event) and store that value in a private member of the class:
hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
WPF manages device independent pixels, so you needs even a converter from dip to real pixel for your screen. This is done with these lines:
var source = PresentationSource.FromVisual(this);
Matrix transformToDevice = source.CompositionTarget.TransformToDevice;
Point[] p = new Point[] { new Point(this.Left + e.HorizontalChange, this.Top), new Point(this.Width - e.HorizontalChange, this.Height) };
transformToDevice.Transform(p);
Finally you can call SetWindowsPos:
SetWindowPos(this.hwndSource.Handle, IntPtr.Zero, Convert.ToInt32(p[0].X), Convert.ToInt32(p[0].Y), Convert.ToInt32(p[1].X), Convert.ToInt32(p[1].Y), SetWindowPosFlags.SWP_SHOWWINDOW);
Sources:
Win32 SetWindowPos
WPF Graphics Rendering
You could wrap your code in a helper method. Just like this:
public static class WindowExtensions {
public static void MoveAndResize( this Window value, double horizontalChange, double verticalChange, double width, double height ) {
value.Left += horizontalChange;
value.Top += verticalChange;
value.Width = width;
value.Height = height;
}
}
So your calling code looks like this:
this.MoveAndResize( 10, 10, 1024, 768 );
I've left off namespace and using declaration, keep that in mind when copying.
Edit:
You could also use the API. Personally I stick with the managed code unless I really need to use the API. But that is up to you.
How to get current mouse coordination on the screen?
I know only Mouse.GetPosition() which get mousePosition of element, but I want to get the coordination without using element.
Or in pure WPF use PointToScreen.
Sample helper method:
// Gets the absolute mouse position, relative to screen
Point GetMousePos() => _window.PointToScreen(Mouse.GetPosition(_window));
To follow up on Rachel's answer.
Here's two ways in which you can get Mouse Screen Coordinates in WPF.
1.Using Windows Forms. Add a reference to System.Windows.Forms
public static Point GetMousePositionWindowsForms()
{
var point = Control.MousePosition;
return new Point(point.X, point.Y);
}
2.Using Win32
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetCursorPos(ref Win32Point pt);
[StructLayout(LayoutKind.Sequential)]
internal struct Win32Point
{
public Int32 X;
public Int32 Y;
};
public static Point GetMousePosition()
{
var w32Mouse = new Win32Point();
GetCursorPos(ref w32Mouse);
return new Point(w32Mouse.X, w32Mouse.Y);
}
Do you want coordinates relative to the screen or the application?
If it's within the application just use:
Mouse.GetPosition(Application.Current.MainWindow);
If not, I believe you can add a reference to System.Windows.Forms and use:
System.Windows.Forms.Control.MousePosition;
If you try a lot of these answers out on different resolutions, computers with multiple monitors, etc. you may find that they don't work reliably. This is because you need to use a transform to get the mouse position relative to the current screen, not the entire viewing area which consists of all your monitors. Something like this...(where "this" is a WPF window).
var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
var mouse = transform.Transform(GetMousePosition());
public System.Windows.Point GetMousePosition()
{
var point = Forms.Control.MousePosition;
return new Point(point.X, point.Y);
}
This works without having to use forms or import any DLLs:
using System.Windows;
using System.Windows.Input;
/// <summary>
/// Gets the current mouse position on screen
/// </summary>
private Point GetMousePosition()
{
// Position of the mouse relative to the window
var position = Mouse.GetPosition(Window);
// Add the window position
return new Point(position.X + Window.Left, position.Y + Window.Top);
}
You may use combination of TimerDispatcher (WPF Timer analog) and Windows "Hooks" to catch cursor position from operational system.
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetCursorPos(out POINT pPoint);
Point is a light struct. It contains only X, Y fields.
public MainWindow()
{
InitializeComponent();
DispatcherTimer dt = new System.Windows.Threading.DispatcherTimer();
dt.Tick += new EventHandler(timer_tick);
dt.Interval = new TimeSpan(0,0,0,0, 50);
dt.Start();
}
private void timer_tick(object sender, EventArgs e)
{
POINT pnt;
GetCursorPos(out pnt);
current_x_box.Text = (pnt.X).ToString();
current_y_box.Text = (pnt.Y).ToString();
}
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}
This solution is also resolving the problem with too often or too infrequent parameter reading so you can adjust it by yourself. But remember about WPF method overload with one arg which is representing ticks not milliseconds.
TimeSpan(50); //ticks
If you're looking for a 1 liner, this does well.
new Point(Mouse.GetPosition(mWindow).X + mWindow.Left, Mouse.GetPosition(mWindow).Y + mWindow.Top)
The + mWindow.Left and + mWindow.Top makes sure the position is in the right place even when the user drags the window around.
Mouse.GetPosition(mWindow) gives you the mouse position relative to the parameter of your choice.
mWindow.PointToScreen() convert the position to a point relative to the screen.
So mWindow.PointToScreen(Mouse.GetPosition(mWindow)) gives you the mouse position relative to the screen, assuming that mWindow is a window(actually, any class derived from System.Windows.Media.Visual will have this function), if you are using this inside a WPF window class, this should work.
I wanna use this code
Point PointA;
private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e) {
PointA = e.MouseDevice.GetPosition(sender as UIElement);
}
private void Button_Click(object sender, RoutedEventArgs e) {
// use PointA Here
}
Our company is developing an application (WPF, targeted to .NET 3.5) with the WPF Diagramming Components from MindFusion.Apparently, printing and saving XPS Documents results in various errors on different systems.
I reduced the problem to a single sample XPS Document created from our application.I'll first give an overview of the concerned systems and break down the issues when respectively saving an xps document and printing the diagram visual using the new WPF Printing Path in the following list:
Note: All three systems have Windows XP SP3 with .NET 3.5 Framework SP1 installed.
Using the XpsDocumentWriter to write a XPS document with the Paginator:
PC 1 - The XPS Viewer (working with IE 7.0) doesn’t work (even after reinstall of .Net 3.5). XPS Viewer from the Essential Pack opens the document, but the view is completely blurred. But as you can see, our application on the right side of the screenshot uses a DocumentViewer to test this issue, which works correctly. Printing from the corrupted XPS Viewer results in the same output as on screen, while printing from the integrated print function in the DocumentViewer ( without intervention from our application) gives a blurry output which is a little more readable, but still not acceptable.
PC 2 - The IE XPS Viewer works correctly. The print ouput is inconsistent. Sometimes, the graphics (Shapes) are not complete, or the printing device notifies about lack of memory (with the same document).
PC 3 – The IE XPS Viewer works correctly, but initiating a print job always leads to this exception within IE itself.
Note: All heretofore mentioned issues have been tested with the XPS Document (already mentioned above) created by our application.
Creating a print job with PrintDialog.PrintDocument and the Paginator:
Printing from our application gives a consistent output with all system: the bigger the document (speaking in term of the page media size), the more blurry it gets. Unfortunately, a lot of potential causes have been already omitted.
The code for printing the document is fairly simple.
• Instead of using our own Paginator, I replaced the latter with another Paginator part of the MindFusion WPF Diagraming Components we use. I achieved the same result. (This statement is also true for XPSDocuments saved as file).
• I used the latest print driver available
• Changes to PrintTicket Resolution doesn’t seem to affect the ouput in any way
• Using another Visual instead of a diagram (like the Window of our Application itself) doesn’t affect the output
Due to these various issues, it seems that multiple causes are also probable. The previous exclusions lead me to assume that some crucial settings are missing in the PrintTicket, or something terribly wrong happens with the XPS to GDI Conversion behnd scenes. Apart from these assumptions, I'm running out of ideas.
Note: All print devices have non-XPS Drivers. HP Designjet 500, HP 2100
Last but not least, I serialised the same PrintTicket used for XPS Document file and the print job.
I would be thankful if anybody has experienced similar issues. Any suggestion is welcome.
I have currently working code but I am still having alignment issues. But print is not blurred I am giving you my code in hope that it may help you and we both could find a solution.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Documents;
using System.Windows;
using System.Windows.Media;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Controls;
using System.Data;
namespace VD
{
public class CustomPaginator : DocumentPaginator
{
private int _RowsPerPage;
private Size _PageSize;
private int _Rows;
public static DataTable dtToPrint;
public CustomPaginator()
{
}
public CustomPaginator(int rows, Size pageSize, DataTable dt)
{
_Rows = rows;
PageSize = pageSize;
dtToPrint = dt;
}
public override DocumentPage GetPage(int pageNumber)
{
int currentRow = _RowsPerPage * pageNumber;
var page = new PageElement(currentRow, Math.Min(_RowsPerPage, _Rows - currentRow))
{
Width = PageSize.Width,
Height = PageSize.Height,
};
page.Measure(PageSize);
page.Arrange(new Rect(new Point(0,0), PageSize));
return new DocumentPage(page);
}
public override bool IsPageCountValid
{ get { return true; } }
public override int PageCount
{ get { return (int)Math.Ceiling(_Rows / (double)_RowsPerPage); } }
public DataTable getDtProtols
{
get
{
return dtToPrint;
}
}
public override Size PageSize
{
get { return _PageSize; }
set
{
_PageSize = value;
_RowsPerPage = PageElement.RowsPerPage(PageSize.Height);
//Can't print anything if you can't fit a row on a page
Debug.Assert(_RowsPerPage > 0);
}
}
public override IDocumentPaginatorSource Source
{ get { return null; } }
}
public class PageElement : UserControl
{
private const int PageMargin = 75;
private const int HeaderHeight = 25;
private const int LineHeight = 20;
private const int ColumnWidth = 140;
private CustomPaginator objParent = new CustomPaginator();
private DataTable ProtocolsDT = null;
private int _CurrentRow;
private int _Rows;
public PageElement(int currentRow, int rows)
{
Margin = new Thickness(PageMargin);
_CurrentRow = currentRow;
_Rows = rows;
}
private static FormattedText MakeText(string text)
{
return new FormattedText(text, CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface("Tahoma"), 14, Brushes.Black);
}
public static int RowsPerPage(double height)
{
return (int)Math.Floor((height - (2 * PageMargin)
- HeaderHeight) / LineHeight);
}
protected override void OnRender(DrawingContext dc)
{
ProtocolsDT = objParent.getDtProtols;
Point curPoint = new Point(0, 0);
dc.DrawText(MakeText("Host Names"),curPoint );
curPoint.X += ColumnWidth;
for (int i = 1; i < ProtocolsDT.Columns.Count; i++)
{
dc.DrawText(MakeText(ProtocolsDT.Columns[i].ToString()), curPoint);
curPoint.X += ColumnWidth;
}
curPoint.X = 0;
curPoint.Y += LineHeight;
dc.DrawRectangle(Brushes.Black, null, new Rect(curPoint, new Size(Width, 2)));
curPoint.Y += HeaderHeight - LineHeight;
Random numberGen = new Random();
//for (int i = _CurrentRow; i < _CurrentRow + _Rows; i++)
//{
// dc.DrawText(MakeText(ProtocolsDT.Rows[i][0].ToString()), curPoint);
//curPoint.X += ColumnWidth;
for (int j = 0; j < ProtocolsDT.Rows.Count; j++)
{
for (int z = 0; z < ProtocolsDT.Rows[j].ItemArray.Length; z++)
{
dc.DrawText(MakeText(ProtocolsDT.Rows[j].ItemArray[z].ToString()), curPoint);
curPoint.X += ColumnWidth;
}
curPoint.Y += LineHeight;
curPoint.X = 0;
//dc.DrawText(MakeText(ProtocolsDT.Rows[j].ItemArray[1].ToString()), curPoint);
//curPoint.X += ColumnWidth;
//dc.DrawText(MakeText(ProtocolsDT.Rows[j].ItemArray[2].ToString()), curPoint);
//curPoint.X += ColumnWidth;
//}
//curPoint.Y += LineHeight;
//curPoint.X = 0;
}
}
}
}
Another Class
private void PrintDataTable(DataTable dt)
{
var printDialog = new PrintDialog();
if (printDialog.ShowDialog() == true)
{
var paginator = new CustomPaginator(dt.Rows.Count,
new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight),dt);
try
{
printDialog.PrintDocument(paginator, "Running Protocols Report");
}
catch (Exception ex)
{
MessageBox.Show(this, "Unable to print protocol information. Please check your printer settings.", "VD", MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK);
}
}
}