무슨 일로 C 하셨습니까?

[C] 소켓 프로그래밍::FTP - UI(1) 본문

C - 이걸 굳이?/FTP

[C] 소켓 프로그래밍::FTP - UI(1)

OJJJ 2021. 3. 31. 16:18

안드로이드나 mfc, wpf 처럼 멋진 GUI를 만들면 좋겠지만

 

C에서는, 뭣보다 내가 원하는 바는 콘솔창에서 UI를 구현하는 것이다.

 

옛날 DOS 감성으로 문자로 UI를 그려서 구현하도록 하겠다.


#include <stdio.h>
#include <windows.h>
#include <io.h>

typedef struct _Painter {
	struct _Line* line;
}Painter;

typedef struct _Line {
	char* data;
	struct _Line* next;
}Line;

아무래도 UI를 구현하게 된다면 고정적으로 출력되는 화면(문자열)이 존재할 것이다.

그러한 화면을 저장하기 위해 리스트 형식의 자료형을 선언하겠다.

 

void Painting(Painter Paint_) {
	system("cls");

	printf("파일 및 폴더 선택==============================\n");

	
	PaintLine(Paint_, 0);

	printf("\n↑,↓ : 이동/ Enter: 선택--------------------\n");
}

void PaintLine(Painter Paint_) {
	// 커서 좌표 이동
	COORD pos = { 0,2 };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);

	Line* line = Paint_.line;

	while (1) {
		if (line == NULL) { 
			puts(""); 
			break; 
		}
		else {
			printf("[  ] %-75s\n", line->data);
			line = line->next;
		}
	}
}

위와 같이 함수가 호출될 때마다 화면을 지우고 화면을 출력하는 식으로 만들면

의도한 대로 만들 수 있다.


이렇게 만든 화면에 이제 컨트롤 요소를 넣어주어야 한다.

int Curser_Run(Painter Paint_) {
	int key;
	int x = 1, y = 2;

	Painting(Paint_);
	int linenum = _LineCount(Paint_);
	_RemoveCursur();
	_Moving(x, y);

	while (1) {
		key = getch();
		// 방향키 & 특수키
		if (key == 224)
		{
			key = getch();
			switch (key) {
			case 72:        // 상
				if (y > 2){
					y--;

					_Moving(x, y);
				}
				break;
			case 75:        // 좌
				break;
			case 77:        // 우
				break;
			case 80:        // 하
				if (y <= linenum){
					y++;

					_Moving(x, y);
				}
				break;
			default:
				//puts("그 외");
				break;
			}
		}
	}
}
더보기

2021.01.25 - [C -이걸 굳이?/유틸리티] - [C] 키보드 이벤트

 

[C] 키보드 이벤트

scanf() 함수를 쓰게되면 콘솔에 키보드 입력을 할 수 있다. 그러나 이러한 방식은 입력된 내용을 엔터 쳐서 넘기는 것인데 이러한 입력말고 콘솔창에서 키보드 입력에 즉각적으로 반응하도록 만

qwerty-ojjj.tistory.com

- 내부에 사용된 함수

void _Moving(int x_, int y_) {
	static x = 1;
	static y = 1;

	// 이전 좌표에 내용 지움
	COORD pos = { x,y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
	printf("  ");

	// 좌표 새로 지정
	pos.X = x_;
	pos.Y = y_;

	// 현 좌표 저장
	x = x_;
	y = y_;

	// 현 좌표에 내용 그리기
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 3);
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
	printf("●");
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
void _RemoveCursur() {
	// 껌뻑껌뻑 커서 지움
	CONSOLE_CURSOR_INFO cursorInfo = { 0, };
	cursorInfo.dwSize = 1;
	cursorInfo.bVisible = FALSE;
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo);
}
int _LineCount(Painter p) {
	Line* ptr = p.line;
	if (ptr == NULL) return 0;

	int count = 0;

	while (1) {
		if (ptr == NULL) return count;

		ptr = ptr->next;
		count++;
	}
}

 

잘 동작하는지 확인하기 위해서는 화면을 만들 필요가 있겠다.

#include "StringFunc.h"

void Painter_Input(Painter* Paint_, char* data_) {
	Line* target = Paint_->line;
	Line* pre = NULL;

	while (1) {
		if (target == NULL) {
			target = (Line*)malloc(sizeof(Line));
			target->data = StringCopy(data_);
			target->next = NULL;

			if (pre == NULL) {
				Paint_->line = target;
			}
			else {
				pre->next = target;
			}
			break;
		}

		pre = target;
		target = target->next;
	}
}

입력한 문자열을 화면으로 구성하는 함수를 만들었다.

 

void main() {
	Painter* p = (Painter*)malloc(sizeof(Painter));
	p->line = NULL;

	Painter_Input(p, "a");
	Painter_Input(p, "b");
	Painter_Input(p, "c");
	Painter_Input(p, "d");
	Painter_Input(p, "e");
	Painter_Input(p, "f");

	Curser_Run(*p);

}

위와 같이 함수를 사용해서 실행시킬 수 있다.

 

화살표를 이용하여 좌표를 움직일 수 있다.( 아직 선택은 구현하지 않았다. )

그런데 이렇게 하면 항목에 따라서 화면의 크기가 바뀐다는 단점이 있다.

 

이러한 점을 보완해보자.

void PaintLine(Painter Paint_, int index) {
...
	// 출력될 라인의 시작 인덱스로 포인터 이동
	for (int i = 0; i < index; i++) {
		line = line->next;
	}
    
	for(int i = 0 ; i <10;i++){
		if (line == NULL)puts(""); 

...
}

출력을 시작할 항목의 위치를 지정.

Line을 출력하는 함수에 while문을 for문으로 변경하여 해당 위치에서 일정 갯수만큼만 출력하게한 후

 

int Curser_Run(Painter Paint_) {
...
	int selected = 0;

	while (1) {
		
        ...
			case 72:        // 상
				// y가 이동할 수 있는 범위
				// 2 <= y <= 11

				if (selected > 0) {
					selected--;
					if (y > 2)
						y--;
					else
						PaintLine(Paint_, selected);

					_Moving(x, y);
				}
				break;
                
		...
			case 80:        // 하
				// linenum : 실제 수 [1부터 시작]
				// selected : index [0부터 시작]
				if (selected < linenum - 1) {
					selected++;

					if (y < 11)
						y++;
					else
						PaintLine(Paint_, selected - 9);

					_Moving(x, y);
				}
				break;
         ...

좌표를 움직이는 함수에 y좌표 외 선택항목을 나타내는 변수를 활용하여

 

10번째 항목 외 항목을 선택할 수 있도록 만든다.

 

 

 

 

Comments