티스토리 뷰

IT/C#

[CS] TextBox Control 선택 영역 비활성화하는 삽질기(Selection Disable)

주인장 진빼이

텍스트 박스 선택영역을 비활성화할 경우가 생겼다.

숫자를 입력받는 경우, 숫자만 입력받아야 하는 경우 그런 컨트롤은 선택영역이 완전히 필요 없었다.

시간을 많이 소비했지만 후회는 없었다.

 

mouse_event 함수를 사용해서 시도해보았으나, CPU가 30% 이상 올라가는 현상이 발생했었다.

-> msdn에서 mouse_event 함수보다 SendInput 함수를 이용하라고 권고하고 있다.

 

stackoverflow에서도 많이 찾아봤지만 완벽한 방법은 없었다.

 

1. 더블 클릭 비활성화

TextBox에 내용을 입력하고 더블클릭을 하면 모든 내용이 선택 영역으로 잡힌다.

더블 클릭을 막기 위해 style에서 DoubleClick 관련 속성(CS_DBLCLICKS)을 false로 설정해보았으나, 변함이 없었다.

찾아보니까 상속받아 만든 컨트롤은 WndProc 방법을 사용해야 한다고 한다.

다음 코드는 더블 클릭 메시지가 발생하면 해당 메시지를 WM_LBUTTONCLICK 메시지로 대체하여 프로시저를 처리하는 것이다.

protected override void WndProc(ref Message m)
{
	// Change WM_LBUTTONDBLCLK to WM_LBUTTONCLICK
	if (m.Msg == 0x203) m.Msg = 0x201;
	base.WndProc(ref m);
}

아주 잘 작동되어 기분이 좋았다.

 

2. 기본 ContextMenu 막기

숫자만 입력하는 컨트롤을 만들 목적이었기에 복사 붙여넣기, 잘라내기, 전체선택이 필요없었다.

그래서 단축키 사용을 막으면서 기본 ContextMenu를 비활성화할 수 있게 ShortcutsEnabled 속성을 false로 변경했다.

this.ShortcutsEnabled = false;

 

3. 선택영역 비활성화

선택 영역을 비활성화 하려면 3가지 정도의 케이스가 존재한다.

사실 3-2와 3-3은 비슷해서 Shift Key만 막는다면 문제 없이 해결되었다.

 

 

3-1. 마우스 드래그 선택 영역 만들기

마우스 드래그를 감지하는건 쉽다. 하지만 드래그를 통해 선택영역이 눈에 보이지 않게 만드는 것은 쉽지 않았다.

드래그를 했을 때 TextBoxControl.SelctionLength 값을 0으로 설정했으나 모두 자연스럽지 못했다.

선택 영역이 보이고 빠르게 사라졌다.

 

인터넷을 찾아봐도 방법을 알 수 없었다. 그러다가 문뜩 고민하니 아..

선택 영역은 결국 마우스를 누르고 있을 때 발생하는거 아닌가?

그럼 마우스를 눌렀을 때 강제로 놓게 만들면 되는 것이 아닌가? (MouseUp Event Call)

그래서 마우스를 강제로 때게 코드를 작성했다. 결과는 매우 성공적이었다.

 

마우스 드래그 상황을 구해서 드래그일 때 마우스를 때는 것이다.

그리고 마우스를 클릭할 시에도 때어줘야 한다. 안그럼 파란색 선택 영역이 가끔 보이다가 사라진다.

마우스만 땟다고 해서 성공하는 것이 아니다. 선택 영역의 길이(SelectionLength)을 모두 0으로 변경해 줘야할 필요가 있었다.

0으로 변경하지 않은 경우 1개의 문자가 선택되는 현상이 발생했다.

private void QuantityBox_MouseMove(object sender, MouseEventArgs e)
{
	if (Drag == true)
	{
		if (this.SelectionLength > 0)
		{
			Rectangle rect = Screen.FromControl(this).Bounds;
			NativeMethods.SendMouseInput(Cursor.Position.X, Cursor.Position.Y, rect.Width, rect.Height, false);
			this.SelectionLength = 0;
			Drag = false;
		}
	}
}

private void QuantityBox_MouseClick(object sender, MouseEventArgs e)
{
	Rectangle rect = Screen.FromControl(this).Bounds;
	NativeMethods.SendMouseInput(Cursor.Position.X, Cursor.Position.Y, rect.Width, rect.Height, false);
	if (Drag == false && e.Button == MouseButtons.Left)
	{
		Drag = true;
	}
}

 

3-2. Shift Key를 이용하여 선택 영역 잡는거 방지하기

Shift Key를 막으려면 그냥 KeyDown이벤트에서 SuppressKeyPress 값을 true로 설정했다.

private void QuantityBox_KeyDown(object sender, KeyEventArgs e)
{
	if (e.Modifiers == Keys.Shift)
	{
		e.SuppressKeyPress = true;
		return;
	}
	e.Handled = false;
}

Shift + 방향키를 이용한 것은 분명 막혔다. 하지만 Shift를 누르고 있을 때 클릭하는 현상은 막아내지 못했다.

 

3-3. Shift  Key + Click을 통한 선택 영역 잡는거 방지하기

이것도 사실 별로 어려울 것이 없었다. SendInput을 사용하여 키가 눌려질 때 다시 키보드를 때게 만들었다.

private void QuantityBox_KeyDown(object sender, KeyEventArgs e)
{
	if (e.Modifiers == Keys.Shift)
	{
		NativeMethods.SendKeyInput(0x10); // Shift Key Code
		e.SuppressKeyPress = true;
		return;
	}
	e.Handled = false;
}

 

 

CPU 사용률도 mouse_event 함수를 사용할 때보다 안전했고, 과부화 같은 것이 걸리지 않아서 좋았다.

단축키가 모두 막혀 사용할 순 없었지만

숫자 입력과 지우기 기능은 아주 잘 작동되었다.

 

왜 TextBox Control의 선택영역을 막으려고 하는가?

만들려던 컨트롤의 목적은 업비트 거래소에서 사용되는 수량 입력기이다.

 

이 수량 입력기의 특징은 숫자를 입력할 수 없고 .은 1번만 입력하는 것이 특징이다.

그리고 일반적인 숫자를 입력하면 1000 단위로 ,가 붙어서 출력되고

만약에 . 이 붙으면 실수로 표현되어야 한다.

컨트롤 하나에 실수와 정수를 표현하는 것이다.

 

선택 영역을 막은 이유는 선택 영역을 통해 캐럿의 위치가 크게 변할 수 있어서 방지한 것이다.

이제 수량 입력기는 한 90% 완벽한거 같다.

아직도 막아야할 케이스가 몇개 보이지만 이대로 써도 충분하다.

 

NativeMethods class는 파일로 첨부한다.

이름을 변경하고, 적당히 수정해서 사용하자. 완벽한 코드는 아니다.

 

nativemethods.txt
0.00MB

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함