AdSense

Showing posts with label Windows Forms. Show all posts
Showing posts with label Windows Forms. Show all posts

Wednesday, 17 July 2013

C# Windows Forms resp. WPF - Save window position and size

(Deutsche Version) It can be very useful when all the windows are at the same position and have same size when restarting an application. Therefor, I wrote an own class in C#: SizeSavedWindow. The source code for the class is below. To save the size and position of a window, you have to add  

SizeSavedWindow.addToSizeSavedWindows(this);

in the InitializeComponent(); method.

This function can be called for many different windows. The windows are saved by name into an xml file, if there are no windows which have the same name, everything works fine. This class also exists for WPF, you simply have to change every "Form" to "Window" and the events have to be modified (window_IsVisibleChanged instead of window_Shown). If anyone is interested in the WPF code i can post this code, too. Now the code for the class SizeSavedWindow:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Runtime.Serialization;
using System.Xml;
using System.Windows.Forms;

namespace KeepSizeTest1
{
    public class SizeSavedWindow
    {
        // To keep a window at the same size and position, just add
        // SizeSavedWindow.addToSizeSavedWindows(this);
        // right after initialieComponent
        public static void addToSizeSavedWindows(Form window)
        {
            window.Shown += window_Shown;
        }

        static void window_Shown(object sender, EventArgs e)
        {
            Form window = (Form)sender;
            if (!window.Visible)
            {
                return;
            }
            if (File.Exists("sizes.xml"))
            {
                var stream = new FileStream("sizes.xml", FileMode.Open);
                var reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
                var deserializer = new DataContractSerializer(typeof(Dictionary<string, int[]>));
                windows = (Dictionary<string, int[]>)deserializer.ReadObject(reader, true);
                stream.Close();

                foreach (KeyValuePair<string, int[]> pair in windows)
                {
                    if (pair.Key == window.Name)
                    {
                        window.Height = pair.Value[0];
                        window.Width = pair.Value[1];
                        window.Top = pair.Value[2];
                        window.Left = pair.Value[3];
                        break;
                    }
                }
            }
            int[] sizes = new int[4];
            sizes[0] = window.Height;
            sizes[1] = window.Width;
            sizes[2] = window.Top;
            sizes[3] = window.Left;
            if (windows.ContainsKey(window.Name))
            {
                windows.Remove(window.Name);
            }
            windows.Add(window.Name, sizes);
            window.SizeChanged += window_SizeChanged;
            window.LocationChanged += window_LocationChanged;
        }

        static void window_SizeChanged(object sender, EventArgs e)
        {
            Form realSender = (Form)sender;
            if (windows.ContainsKey(realSender.Name))
            {
                windows[realSender.Name][0] = realSender.Height;
                windows[realSender.Name][1] = realSender.Width;

                var writer = new FileStream("sizes.xml", FileMode.Create);
                Type type = windows.GetType();
                var serializer = new DataContractSerializer(type);
                serializer.WriteObject(writer, windows);
                writer.Close();
            }
        }

        static void window_LocationChanged(object sender, EventArgs e)
        {
            Form realSender = (Form)sender;
            if (windows.ContainsKey(realSender.Name))
            {
                windows[realSender.Name][2] = realSender.Top;
                windows[realSender.Name][3] = realSender.Left;

                var writer = new FileStream("sizes.xml", FileMode.Create);
                Type type = windows.GetType();
                var serializer = new DataContractSerializer(type);
                serializer.WriteObject(writer, windows);
                writer.Close();
            }
        }

        static Dictionary<string, int[]> windows = new Dictionary<string, int[]>();
    }
}

Friday, 12 July 2013

C# - Access joystick

(Deutsche Version) In this post I will show how to access a joystick in C#. I use the joystick project from here, I just put everything into a new Windows Forms project into a class Joystick.cs (DirectX had to be included, more information about that is provided here). I modified the project a bit, more about that later.

My program (e.g. to read the x-axis) looks like this:

public partial class Form1 : Form
{
    Joystick.Joystick joystick;
    public Form1()
    {
        InitializeComponent();
        joystick = new Joystick.Joystick(this, true);
        joystick.PushChange += joystick_PushChange;
        joystick.AxeChanged += joystick_AxeChanged;
    }

    void joystick_AxeChanged(int X, int Y, int Z, int Rz)
    {
        System.Console.Write("Axis: {0}\t{1}\t{2}\t{3}\n", X, Y, Z, Rz);
    }

    void joystick_PushChange(int Push)
    {
        System.Console.Write("Push: {0}\n", Push);
    }
}


With this project, you can do lots of things, e.g. control Panzerkampf via joystick. Luckily there are events for everything (Key pressed, axe changed, ...) so you should be able to do everything with this project.

If anyone want to access multiple joysticks, you have to use the modified version of the project: JoystickMultiple. The basic principle is the same, you can use the joystick project the same way as before but you also can read single joysticks. This works like this:

Dictionary<Guid, string> foundSticks = Joystick.Joystick.GetAllJoysticks();
foreach (KeyValuePair<Guid, string> pair in foundSticks)
{
    Joystick.Joystick localStick = new Joystick.Joystick(this, false, pair.Key);
    System.Console.Write("stick: {0}\n", pair.Value);
    localStick.ButtonDown += joystick_ButtonDown;
}


joystick_ButtonDown is the following:

void joystick_ButtonDown(int ButtonNumber, Joystick.Joystick stick)
{
    System.Console.Write("{1} - Button: {0}\n", ButtonNumber, stick.Name);
}


In the modified project, every event also returns the joystick. Similar to DirectSound, the app.config has to be modyfied: <startup> has to be changed to <startup useLegacyV2RuntimeActivationPolicy="true">, otherwise the program will not start.

Monday, 17 June 2013

C# - DirectSound

(Deutsche Version) For Panzerkampf I needed sounds. the basic sound play methon in C# is not able to play multiple sounds parallel (the current playing sound will be canceled when a new one is started). Therefor I had to install DirectSound from DirectX. For DirectX, the DirectX SDK is needed.


Previous to the installation, you should remove "Microsoft Visual C++ 2010 Redistributable", otherwise the error "S1023" occurs (here is more information about this error).

After the installation, you only need to add a reference in the C# project (Browse - Microsoft.DirectX.DirectSound, I found the file at C:\Windows\assembly\GAC\Microsoft.DirectX.DirectSound).


Additionally, App.config has to be modified a bit. At first it looked like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>


<startup> has to be modified to <startup useLegacyV2RuntimeActivationPolicy="true">, now everything looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup useLegacyV2RuntimeActivationPolicy="true">
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>


The code to play sounds is the following:

Device applicationDevice = new Device();
applicationDevice.SetCooperativeLevel(this, CooperativeLevel.Priority );

soundBuffer1 = new SecondaryBuffer( "c:\afile1.wav", applicationDevice );
soundBuffer2 = new SecondaryBuffer( "c:\afile2.wav", applicationDevice );

soundBuffer1.Play( 0, BufferPlayFlags.Looping );
soundBuffer2.Play( 0, BufferPlayFlags.Looping );


Friday, 14 June 2013

C# Windows Forms - Draw double buffered

(Deutsche Version) To draw everything in Panzerkampf, I used Windows Forms. A redraw event is deleting everything and then re-painting everything. This causes a very annoying flickering. To avoid this, everything is painted into an image and then the image is painted on the actual view - which will not be cleared because the image covers everything. This solves the flickering problem. Here is the code:

void drawDoubleBufBmp()
{
    Bitmap localBitmap = new Bitmap(settings.SizeX, settings.SizeY);
    using (Graphics gx = Graphics.FromImage(localBitmap))
    {
        gx.DrawDrawString("Panz.....");
    }
    lock (BmpLock)
    {
        doubleBufBmp = localBitmap;
    }
}


private Bitmap doubleBufBmp = new Bitmap(settings.SizeX, settings.SizeY);
private object BmpLock = new object();
protected override void OnPaint(PaintEventArgs e)
{
    lock (BmpLock)
    {
        g.DrawImage(doubleBufBmp, 0, 0);
    }
}

protected override void OnPaintBackground(PaintEventArgs e)
{}


I had to overwrite OnPaintBackground because this was causing the flickering. In the OnPaint function, I simply draw the complete doubleBufBmp in the Window. drawDoubleBufBmp() is called by a thread every 10 milliseconds, which then calls this.Invalidate(); which causes the OnPaint function to be called.

Monday, 20 May 2013

C# Windows Forms - Rotate image

(Deutsche Version) For Panzerkampf it is necessary to rotate an image. The solution which I use is:

private Image rotateImage(Image b, double angle)
{
  //create a new empty bitmap to hold rotated image
  Bitmap returnBitmap = new Bitmap(2*b.Width, 2*b.Height);
  //make a graphics object from the empty bitmap
  Graphics g = Graphics.FromImage(returnBitmap);
  //move rotation point to center of image
  g.TranslateTransform(center_x, center_y);
  //rotate
  g.RotateTransform(-(float)(angle*180.0/Math.PI));
  //move image back
  g.TranslateTransform(-center_x, -center_y);
  //draw passed in image onto graphics object
  g.DrawImage(b, new Point(0, 0));
  return returnBitmap;
}

Panzerkampf

(Deutsche Version) Some years ago, I programmed a game for Linux called Panzerkampf (translated: Tank fight). The basic idea was to navigate a tank via arrows/WASD through the environment and try to kill the other player. Sadly this project was limited by many factors: A single keyboard cannot handle enough keys so it could happen that one player could not shoot anymore.

About two weeks ago, I started to program the game again. The game is written in C# and can be played via internet or local area network. The network communication is running with sockets, here the basic code snippet:

Client:

System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
clientSocket.Connect("mein.server.de", port);
NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes("message to server");
//Nachricht an Server senden
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
byte[] inStream = new byte[70000];
//inStream anpassen (größe an clientSocket.ReceiveBufferSize anpassen)
Array.Resize(ref inStream, clientSocket.ReceiveBufferSize);
//Nachricht vom Server empfangen
serverStream.Read(inStream, 0, clientSocket.ReceiveBufferSize);
string dataFromServer = System.Text.Encoding.ASCII.GetString(inStream);
clientSocket.Close();


Server:

TcpListener serverSocket = new TcpListener(port);
TcpClient clientSocket = default(TcpClient);
serverSocket.Start();
clientSocket = serverSocket.AcceptTcpClient();
NetworkStream networkStream = clientSocket.GetStream();
byte[] bytesFrom = new byte[10025];
Array.Resize(ref bytesFrom, clientSocket.ReceiveBufferSize);
networkStream.Read(bytesFrom, 0, clientSocket.ReceiveBufferSize);
string dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
Byte[] sendBytes = Encoding.ASCII.GetBytes("message to Client");
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
clientSocket.Close();


For the sounds I used sounds from freesound.org which are under the Creative Commons 0 license, I do not have to refer to the creators but I am not allowed to say that the sounds would belong to me.

The graphics are made with windows forms.

The download for the client is here: http://physudo.bplaced.net/Panzerkampf/publish.htm
And for the server here: http://physudo.bplaced.net/PanzerkampfServer/publish.htm

If anyone plays Panzerkampf, I would be glad to receive a small feedback (maybe as comment to this post)