디자인 문서개요는 컨트롤들의 순서 등 정리가 아주 편리합니다. (특히 도킹 관련해서 순서 지정이 가능!)

(+ 꿀팁 : 컨트롤에 포커싱 있는 상태에서 ESC 키를 통해 상위 컨트롤로 선택이 가능합니다.)

 

보기 => 다른 창 => 문서 개요  를 통해 복잡한 오브젝트를 쉽게 볼 수 있습니다.

 

문서 개요 매뉴

 

왼쪽 문서 개요 뷰에서 요소의 순서를 바꾸거나 삽입 / 제거 도 쉽답니다.

 

간단한 구조가 마음에 들어 까먹기 전에 다시 작성해두기!

using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows.Forms;

namespace LogTest
{
    public enum LogLevel
    {
        Debug, Info, Error
    }

    public static class Log
    {
        private static LogLevel logLevel;
        private static string logPath;

        public static void Init(LogLevel level) //최초 한번 실행해주기!
        {
            logLevel = level;

            //폴더 등 설정
            logPath = Path.Combine(Application.StartupPath, "test.log");
            //기존 불필요한 로그 삭제하기.
        }

        public static void Write(string message, LogLevel level, [CallerMemberName] string callFunction = "")
        {
            if (logLevel <= level)
            {
                string type = level.ToString();

                string logContent = string.Format("[{0}] {1} ({2}) : {3}{4}",
                                                type, DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"), callFunction, message, Environment.NewLine);

                File.AppendAllText(logPath, logContent);
            }
        }
    }
}

세 개의 버튼을 만들고 테스트 해봅시다.

 

프로그램 중간에 종료를 시켜야 하는 경우 위의 3가지 방식을 사용할 수 있습니다.

각 특징은 아래와 같습니다.

 

Close() : 해당되는 폼만 닫습니다.

                

Application.Exit() : 다른 서브 폼에서 호출 해도 메인 폼의 Close()까지 동작되게 됩니다.

 

Environment.Exit(0) : 이 곳에서 바로 종료됩니다.

 

using System;
using System.Windows.Forms;

namespace CloseTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Close();
            //이 후 로직도 타게 됩니다.
            //무언가 로직 실행... (+ FormClosing)
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Application.Exit();
            //이 후 로직도 타게 됩니다.
            //무언가 로직 실행... (+ FormClosing)
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Environment.Exit(0);
            //바로 종료 됩니다. (FormClosing을 타지 않습니다.)
            //실행되지 않는 이 후 로직!
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //Close(), Application.Exit() 시에 이 곳까지 도달합니다.

            e.Cancel = true; //프로그램이 종료되지 못하도록 막습니다.
        }
    }
}

base64 바이트를 이용한 파일 읽기 / 생성

 

base64를 통해 파일을 바이트 혹은 "텍스트" 형태로 주고 받을 수 있습니다.

using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;

namespace Base64
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            //텍스트가 길어질 수 있으니 늘려줍니다.
            //혹은 파일을 읽어도 괜찮겠네요.
            textBox1.MaxLength = 100000000;
        }

        private void button_fileToBase64_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string filePath = openFileDialog.FileName;
                byte[] fileBytes = File.ReadAllBytes(filePath); //바이트로 파일을 읽어온 후
                char[] fileToBase64 = new char[(int)Math.Ceiling(fileBytes.Length * 1.5)]; //base64는 33% 증가!
                Convert.ToBase64CharArray(fileBytes, 0, fileBytes.Length, fileToBase64, 0); //base64로 만들어줍니다.

                MessageBox.Show(fileBytes.Length + " " + fileToBase64.Length);

                Clipboard.SetText(new string(fileToBase64)); //클립보드에 복사해줍니다. string으로 만들어서!
            }
        }

        private void button_base64ToFile_Click(object sender, EventArgs e)
        {
            string text = textBox1.Text;
            byte[] textBytes = Convert.FromBase64String(text); //위의 string을 다시 base64 byte로 만들어줍니다.

            string folder = Directory.GetCurrentDirectory();
            string filePath = Path.Combine(folder, "file");
            File.WriteAllBytes(filePath, textBytes); //해당 값으로 파일을 만들어줍니다.

            Process.Start(folder); //파일 생성 확인용 폴더 띄워주기
        }
    }
}

 

Alt + Tab 시 Form이 화면에 노출 됩니다.

 

아래 소스를 통해 탭에서 해당 폼을 볼 수 없도록 만들 수 있습니다.

Form3이 있지만 테스크 변경에서 보이지 않게 됩니다.

using System.Windows.Forms;

namespace DrawString
{
    public partial class Form3 : Form
    {
        public Form3()
        {
            InitializeComponent();

            this.ShowInTaskbar = false;
            this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
        }

        //this.FormBorderStyle = FormBorderStyle.FixedToolWindow; 와 동일한 동작을 합니다.
        //protected override CreateParams CreateParams
        //{
        //    get
        //    {
        //        CreateParams cp = base.CreateParams;
        //        cp.ExStyle |= 0x80;
        //        return cp;
        //    }
        //}
    }
}

    //아래 두형태에 대해서는 Alt+Tab에서 보이지 않게 되는군요!
    public enum FormBorderStyle
    {
        ...
        // 요약:
        //     크기를 조정할 수 없는 도구 창 테두리입니다. 사용자가 ALT + TAB을 누를 때 표시 되는 창 또는 작업 표시줄에는 도구 창이 나타나지
        //     않습니다. 지정 하는 폼 있지만 System.Windows.Forms.FormBorderStyle.FixedToolWindow 일반적으로에
        //     표시 되지 않은 작업 표시줄을 확인 해야는 System.Windows.Forms.Form.ShowInTaskbar 속성이 false, 기본값
        //     이므로, true합니다.
        FixedToolWindow = 5,
        //
        // 요약:
        //     크기 조정 가능한 도구 창 테두리입니다. 사용자가 ALT + TAB을 누를 때 표시 되는 창 또는 작업 표시줄에는 도구 창이 나타나지 않습니다.
        SizableToolWindow = 6
    }

 

 

이미지 등 컨트롤 위에 투명한 Form이 위치한 모습!

 

Winform에는 Z인덱스가 없더군요. 약간의 트릭을 써서 위와같은 형태를 만들 수 있었습니다.

(화면만 가려질 뿐 뒷쪽과 상호작용 가능합니다)

 

간단한 구조를 먼저 보자면..

 

1. 새로운 Form을 만들어 줍니다.

2. 새로운 Form에 WndProc 를 수정하여 통해 뒷쪽 컨트롤에게 이벤트를 넘겨줄 수 있도록 수정합니다.

3. OnPaint를 통해 문자를 그려줍니다.

4. Form의 소유자를 지정하여 소유자 상단에 위치하도록 해줍니다.

 

아래는 2개의 폼에 대한 코드입니다.

 

[Form1.cs]

using System;
using System.Drawing;
using System.Windows.Forms;

namespace DrawString
{
    public partial class Form1 : Form
    {
        private Form2 form2 = new Form2();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            form2.Show();
            form2.Owner = this; //[4번] form1가 form2를 소유하여 상단에 위치시킵니다. (매우 중요)

            pictureBox1.Image = Image.FromFile(@"C:\Users\dlaeh\Desktop\test.tif");
            pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
            ShowTransparentForm();
        }

        private void ShowTransparentForm ()
        {
            int offsetY = 30;
        
            //크기에 맞춰 수정 가능합니다!
            form2.Size = new Size(this.Width - 16, pictureBox1.Size.Height);
            form2.Location = new Point(this.Location.X + 8,
                                       this.Location.Y + pictureBox1.Location.Y + offsetY);
        }

        private void Form1_Resize(object sender, EventArgs e) //크기 변경 시 맞춰서 변경
        {
            ShowTransparentForm();
            form2.Refresh(); //Form을 수동으로 늘리면 텍스트가 짤리더군요!
        }

        private void Form1_Move(object sender, EventArgs e) //이동 시에 위치 변경
        {
            ShowTransparentForm();
        }
    }
}

 

 

[Form2.cs]

using System;
using System.Drawing;
using System.Windows.Forms;

namespace DrawString
{
    public partial class Form2 : Form
    {
        private const int WM_NCHITTEST = 0x84; //마우스 커서 위치 메시지
        private const int HTTRANSPARENT = -1; //뒷쪽의 컨트롤에 메시지를 넘깁니다.

        public Form2()
        {
            InitializeComponent();

            this.Enabled = false; //상호작용 안하기 위해
            this.FormBorderStyle = FormBorderStyle.None; //기본폼으로
            this.Opacity = 0.5; //투명도
            this.ShowInTaskbar = false; //Alt + Tab 등 선택 방지

            //for test
            this.BackColor = Color.Black;
        }

        //[2번]
        //WM_NCHITTEST 와 HTTRANSPARENT 관련 공식사이트
        //https://learn.microsoft.com/ko-kr/windows/win32/inputdev/wm-nchittest
        protected override void WndProc(ref Message message)
        {
            if (message.Msg == WM_NCHITTEST) //마우스 커서 위치 메시지
            {
                message.Result = (IntPtr)HTTRANSPARENT; // 뒷쪽의 컨트롤에 메시지를 넘깁니다.
            }
            else
            {
                base.WndProc(ref message);
            }
        }


        private int offsetX = 200;
        private int offsetY = 300;
        private int rotateOffsetY = 30;
        private int rotate = 30;

        protected override void OnPaint(PaintEventArgs e) //[3번] 그려주기!
        {
            Graphics graphics = e.Graphics;

            SolidBrush myBrush = new SolidBrush(Color.FromArgb(50, 255, 50, 50));

            for (int i = 0; i * offsetY + rotateOffsetY <= this.Size.Height; ++i)
            {
                graphics.TranslateTransform(0, i * offsetY + rotateOffsetY);

                for (int j = 0; j * offsetX <= this.Size.Width; ++j)
                {
                    graphics.TranslateTransform(offsetX, 0);
                    graphics.RotateTransform(-rotate);
                    graphics.DrawString("2024-02-11 !@#@##@ test~~", new Font(FontFamily.GenericSansSerif, 15, FontStyle.Bold), myBrush, Point.Empty);
                    graphics.RotateTransform(rotate);
                }
                
                graphics.ResetTransform();
            }

            graphics.ResetTransform();
            base.OnPaint(e);
        }
    }
}

 

도구 -> 옵션 -> 환경 -> 클라이언트 성능에 따른 시각적 효과 자동 조정 항목 체크를 해주면 됩니다.

 

파일 저장, 불러오기 등에 사용되는 옵션이 있습니다.

 

양식은

(2개 이상 받기)

설명문|파일확장자;파일확장자2

 

(1개씩 받기)

파일명1 | 파일1확장자 | 파일2 | 파일2확장자

형태로 입력하면 됩니다.

 

 

using System.Windows.Forms;

namespace WindowsFormsApp_searching
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();

            openFileDialog.Filter = "Tif(Tiff),JPG|*.tif;*.jpg|ALL|*.*";

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                //선택 된 경우!
            }
        }
    }
}

프로젝트에 리소스를 등록하여 사용하는 방법을 알아보겠습니다.

Properties.Resources.  을 이용하여 접근 가능합니다.

 

먼저 완성된 코드와 그림입니다.

using System.Windows.Forms;

namespace WindowsFormsApp_searching
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            label1.Text = Properties.Resources.TestString;
            pictureBox1.Image = Properties.Resources.myImage;
        }
    }
}

 

 

1. 프로젝트 오른쪽 클릭하고 속성을 눌러줍니다.

 

 

2. 리소스 탭을 클릭하면 기본 문자열에 대해 입력이 가능해집니다.

 

3. 문자열 외에도 여러 리소스를 등록할 수 있습니다. (이미지 등록 등은 드래그 앤 드롭해서 사용해주면 됩니다!)

Process.Start 혹은 Process 클래스를 구현하여 사용하여 프로그램 실행이 가능합니다.

아래는 엑셀, 텍스트 문서를 열은 예제입니다.

using System;
using System.Diagnostics;
using System.IO;

namespace ConsoleApp
{    
    class Program
    {
        public static void Main(string[] args)
        { 
            Process process = new Process();

            /* 프로그램 실행 시키고 기다리기.
            Process pro = Process.Start("...");
            pro.WaitForExit();
            */

            Console.WriteLine("[Excel] 프로세스 시작!");

            process.StartInfo.Arguments = Path.Combine(Directory.GetCurrentDirectory(), "test.xlsx");
            process.StartInfo.FileName = "excel.exe";
            process.StartInfo.UseShellExecute = true; //엑셀 실행 시 UseShellExecute 필요!

            process.Start();
            process.WaitForExit();

            //위와 동일한 작업을 합니다!
            //Process pro = Process.Start(new ProcessStartInfo("excel.exe", Path.Combine(Directory.GetCurrentDirectory(), "test.xlsx")) { UseShellExecute = true });
            //pro.WaitForExit();

            Console.WriteLine("[Excel] 프로세스 종료!");

            Console.WriteLine("[notepad] 프로세스 시작!");

            process.StartInfo.Arguments = Path.Combine(Directory.GetCurrentDirectory(), "test.txt");
            process.StartInfo.FileName = "notepad.exe";

            process.Start();
            process.WaitForExit();

            Console.WriteLine("[notepad] 프로세스 종료!");
        }
    }
}

 

결과! (해당 경로에 파일이 있어야 열립니다)

 

+ Recent posts