Текстовый режим
От: RRR500  
Дата: 06.10.09 19:35
Оценка:
В старых компиляторах (например, Borland C 3.1) в заголовчном файле conio.h были функции clrscr, gotoxy и textattr. В Visual Studio 2005 перечисленные функции отсутствуют. Как же тогда в консольном приложении установить цвет символа или переместить курсор в какую-либо точку экрана?

08.10.09 20:06: Перенесено модератором из 'C/C++' — Кодт
Re: Текстовый режим
От: MasterZiv СССР  
Дата: 06.10.09 19:44
Оценка:
RRR500 пишет:

> В старых компиляторах (например, Borland C 3.1) в заголовчном файле

> conio.h были функции clrscr, gotoxy и textattr.

Это были нестандартные функции.

В Visual Studio 2005
> перечисленные функции отсутствуют.

Ну, а с какой бы ? У них свои были, другие.
В винде их уже нет, естественно.

Как же тогда в консольном приложении
> установить цвет символа или переместить курсор в какую-либо точку экрана?

Универсально, стандартно -- никак.
В конкретной ОС на то есть конкретные API: Console API в Win32,
(N)Curses или SLang -- в *NIX.
Posted via RSDN NNTP Server 2.1 beta
Re: Текстовый режим
От: vadimcher  
Дата: 06.10.09 20:26
Оценка: 24 (5)
Здравствуйте, RRR500, Вы писали:

RRR>В старых компиляторах (например, Borland C 3.1) в заголовчном файле conio.h были функции clrscr, gotoxy и textattr. В Visual Studio 2005 перечисленные функции отсутствуют. Как же тогда в консольном приложении установить цвет символа или переместить курсор в какую-либо точку экрана?


Консольное приложение -- это не то же самое, что текстовый режим в старых ОС, это своего рода эмуляция. Лучше всего создать соответствующий класс для работы с консолью. По порядку.
0) Конструктор. Тебе просто необходимо получить хотя бы один WHND -- на запись. Может понадобиться и другой, на чтение. Поэтому начнем с этого:
    rHND = GetStdHandle(STD_INPUT_HANDLE);
    wHND = GetStdHandle(STD_OUTPUT_HANDLE);
    Init(title, width_, height_, height_buf_);

Здесь Init вызывает инициализацию, описанную в следующем пункте (она вынесена в отдельный метод, чтобы ее можно было вызывать и позже).

1) Инициализация.
* Надпись сверху (title). Передадим в Init строку, которую надо отобразить сверху.
if (title) SetConsoleTitle(title);

* Размер экрана и размер буфера. Размер экрана в консольном приложении -- это размер, который ты видишь на экране. Размер буфера -- это размер всего экрана, который можно скроллить. Размер экрана не может быть меньше размера буфера. Сделаем чуть проще, пусть в нашем случае ширина экрана и буфера одинаковая, а высота буфера может быть больше. Передадим в Init три переменные: width, height, height_buf.
Далее, основная сложность в установке размера экрана и буфера в том, что если, например, ты установишь размер экрана меньше размера буфера, то твой вызов просто проигнорируется, а изначальные размеры неизвестны. Например, если ты сначала установишь размер буфера, то он может оказаться меньше текущего размера экрана. Если ты сначала установишь размер экрана, то он может оказаться больше размера буфера.
Поэтому сделаем так:
— если ширина буфера сейчас меньше того, что хотим, то изменим ширину
— если высота буфера сейчас меньше того, что хотим, то изменим высоту
Это гарантировано не сделает буфер меньше, т.е. текущий экран "влезет", кроме того, это гарантировано не оставляет размер буфера меньше нового размера экрана.
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(wHND, &info);
COORD bufferSize = info.dwSize;
if (bufferSize.X <= width) bufferSize.X = width;
if (bufferSize.Y <= height_buf) bufferSize.Y = height_buf;
SetConsoleScreenBufferSize(wHND, bufferSize);

— изменим размеры экрана: буфер должен быть достаточным для нового экрана.
SMALL_RECT windowSize = { 0, 0, width - 1, height - 1 };
SetConsoleWindowInfo(wHND, true, &windowSize);

— изменим размеры буфера: новый размер экрана, буфер можно спокойно изменять.
bufferSize.X = width;
bufferSize.Y = height_buf;
SetConsoleScreenBufferSize(wHND, bufferSize);

Это чуть ли не единственный вариант, который у меня работал безупречно. Кстати, подобной информации я нигде не видел и нашел опытным путем, пытаясь понять, почему у меня под Vista-ой программа в режиме Debug устанавливала размер экрана нормально, а в Release -- нет. Так что, это, можно сказать, опыт борьбы с непонятными глюками, который можно бесплатно перенять.

2) Курсор. Координаты курсора меряются в абсолютных координатах (относительно буфера), а не в относительных. С этим надо быть тоже осторожным. Особенно, если ты выводишь что-то в последней строке и буфер сдвигается вверх.
Получить курсор.
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(wHND, &info);
return info.dwCursorPosition;

Установить курсор.
COORD xy;
SetConsoleCursorPosition(wHND, xy);


3) Нарисовать чего-нибудь. Здесь у меня лично отдельный класс, который называется ScreenBuffer. Цель его -- хранить данные для прямоугольника, который потом выводится на экран. Из чего состоит ScreenBuffer? Свойства: ширина, высота, курсор, текуший атрибут (цвет текста и цвет фона), и, главное, сам буфер:
CHAR_INFO * buf;

CHAR_INFO -- это наподобие старого ДОС'кого текстового режима, где на каждый символ хранится информация о самом символе, о его цвете и цвете фона.
Инициализация буфера состоит в установке его ширины, высоты и атрибута, а также выделении памяти под него. Далее, есть ряд функций таких, как очистка экрана, например, и т.п. Кроме того, есть стандартные операции типа operator << (char ch); Я еще добавил манипуляторы туда для установки ширины вывода и прочего. И т.п. Все это реализуется элементарно и WinAPI здесь ни при чем. Вывод буфера. Буфер может выводиться либо в другой буфер, либо на консоль. В первом случае -- это просто дело техники скопировать данные из одного буфера в другой, а во втором случае нам понадобится что-то вроде этого (выводим ScreenBuffer buf на экран в точке x,y):
COORD bufsize = { buf.width, buf.height };
COORD bufcoord = { 0, 0 };
SMALL_RECT reg = { x, y, x + bufsize.X - 1, y + bufsize.Y - 1 };
WriteConsoleOutput(wHND, buf.buf, bufsize, bufcoord, &reg);


4) Последнее. Использование буферов достаточно удобно. Например, использование буферов в моем случае можно посмотреть здесь
Автор: vadimcher
Дата: 10.08.09
. Это в первую очередь удобно, если есть какие-то "панели", в которых периодически изменяем данные, но в целом внешний вид остается прежним. Другой пример -- Far. Если же требуется просто выводить строчку красным цветом вверху экрана, то можно обойтись стандартным cout << ..., установив при этом курсор в нужное место и соответствующие атрибуты выводимого текста.

Поиск по ключевым WinAPI функциям, которые я здесь привел, поможет тебе в дальнейшем исследовании.

P.S. Главный минус использования консоли в том, что программа становится совсем не кроссплатформенной, даже более того, насколько я помню, все эти замечательные WinAPI функции стали доступны после win2000.

А вот зайца кому, зайца-выбегайца?!
Re[2]: Текстовый режим
От: Кодт Россия  
Дата: 06.10.09 21:32
Оценка: 1 (1)
Здравствуйте, MasterZiv, Вы писали:

MZ>Универсально, стандартно -- никак.

MZ>В конкретной ОС на то есть конкретные API: Console API в Win32,
MZ>(N)Curses или SLang -- в *NIX.

Как насчёт порта каких-нибудь *curses?
Вот сейчас нашёл некие tiny curses, якобы кроссплатформенные и приспособленные к VC++
http://code.google.com/p/tinycurses/
Для человека, привычного к conio, эта библиотека не должна вызвать культурный шок.
Перекуём баги на фичи!
Re[3]: Текстовый режим
От: Кодт Россия  
Дата: 06.10.09 21:37
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Вот сейчас нашёл некие tiny curses, якобы кроссплатформенные и приспособленные к VC++


Похоже, что как раз не кроссплатформенные, а чисто винапишные. То есть, минимальное подмножество curses поверх WinAPI.
Ну и тоже хорошо. А потом, когда захочется перепереть под никсы, не будет слишком много сложностей — в отличие от работы с Console API напрямую.
Перекуём баги на фичи!
Re[3]: Текстовый режим
От: MasterZiv СССР  
Дата: 07.10.09 07:38
Оценка:
Кодт пишет:

> Как насчёт порта каких-нибудь *curses?

> Вот сейчас нашёл некие tiny curses, якобы кроссплатформенные и
> приспособленные к VC++

Да ncurses и так кросс-платформенный. Только вот с каких
пор он в стандарт вошёл — я не понимаю.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: Текстовый режим
От: maykie Россия  
Дата: 07.10.09 09:31
Оценка:
Здравствуйте, Кодт, Вы писали:


К>Как насчёт порта каких-нибудь *curses?

К>Вот сейчас нашёл некие tiny curses, якобы кроссплатформенные и приспособленные к VC++
К>http://code.google.com/p/tinycurses/
К>Для человека, привычного к conio, эта библиотека не должна вызвать культурный шок.

Есть PDCurses. Public Domain Curses. Работают в том числе и под виндой. Вроде даже могут немного дружить с юникодом, если их попросить.
Re[4]: Текстовый режим
От: Кодт Россия  
Дата: 07.10.09 10:04
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Да ncurses и так кросс-платформенный. Только вот с каких пор он в стандарт вошёл — я не понимаю.


Речь не о том, чтобы в стандарт вошёл, а в том, что идёт в поставке компилятора.
(Или что можно поставить дополнительно).
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[2]: Текстовый режим
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.12.09 08:55
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>P.S. Главный минус использования консоли в том, что программа становится совсем не кроссплатформенной, даже более того, насколько я помню, все эти замечательные WinAPI функции стали доступны после win2000.


В последнем что-то не так — я их успешно использовал в Win95. Может, речь про unicode версии? там действительно были тонкости с этим.
The God is real, unless declared integer.
Re[3]: Текстовый режим
От: vadimcher  
Дата: 19.12.09 11:47
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, vadimcher, Вы писали:


V>>P.S. Главный минус использования консоли в том, что программа становится совсем не кроссплатформенной, даже более того, насколько я помню, все эти замечательные WinAPI функции стали доступны после win2000.


N>В последнем что-то не так — я их успешно использовал в Win95. Может, речь про unicode версии? там действительно были тонкости с этим.


Некоторые -- да, а некоторые стали доступны только в Win2000, я уж не помню всех тонкостей.

А вот зайца кому, зайца-выбегайца?!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.