консоль в окне под win32

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

консоль в окне под win32

Сообщение nagash » 21.05.2007 10:36:24

Такая проблема... Нужно облагородить консоль) Т.е. идея - создать окно, а в нем нечто вроде консоли, как отдельный элемент.
К сожалению моих познаний в программировании не хватает, недавно только перешел на fpc с обычного паскаля. Все что я смог - создать пустое окошко с надписью 'Hello world!')
Помогите пожалуйста, просьба не тыкать в мануалы - мне нужно решение конкретной проблемы, а не умение работать с окнами.
Спасибо :)
nagash
новенький
 
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05

Сообщение shade » 21.05.2007 11:32:20

Интересная задачка, тоже над ней как-то думал. Даже что-то пытался написать (на Dephi), но опыт был не очень удачный.

http://the1st.adygnet.ru/~ftp/pub/examp ... /Mycmd.zip

Единственное, что приходит на ум, так это написать с нуля свой элемент управления, хотя можно по-пробовать развить мой старый пример. Там основная проблема с перенаправлением ввода-вывода (его нужно полностью переделать, о том как см. http://freepascal.ru/forum/viewtopic.php?t=2311 ), скорее всего есть еще какие проблемы - давно писал не помню
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение nagash » 21.05.2007 14:15:31

Спасибо за инфу, гляну вечером.
Ммм.... думал что все это проще сделать) По-моему в моем случае проще забить на консоль и переписать программу целиком под винду. А так я просто хотел совместить консольный вариант с кнопочным интерфейсом...
nagash
новенький
 
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05

Сообщение shade » 21.05.2007 14:33:32

nagash писал(а):А так я просто хотел совместить консольный вариант с кнопочным интерфейсом...

Ну если так, то все действительно просто. Под Windows нужно просто заменить директиву {$APPTYPE GUI} на {$APPTYPE CONSOLE} и кроме окошек будет висеть консоль. Так же под Windows можно использовать WinAPI: AllocConsole|FreeConsole

Под *nix вообще нет явного деления на конные и консольные программы, можно спокойно использовать и то и другое.

Но обычно делаться консольная утилита и к ней граф интерфейс. Или делается библиотека, а ее использует оконное приложение и консольное..
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение nagash » 21.05.2007 14:58:33

shade писал(а):Под Windows нужно просто заменить директиву {$APPTYPE GUI} на {$APPTYPE CONSOLE}


Я немного не так выразился. Мне нужно чтобы вывод консоли был частью интерфейса окна, т.е. как раз то, о чем написано выше :roll:
Щас глянул Mycmd.zip. Без ста грамм не разберусь, опыта не хватает(
nagash
новенький
 
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05

Сообщение shade » 21.05.2007 15:44:18

nagash писал(а):Щас глянул Mycmd.zip. Без ста грамм не разберусь, опыта не хватает(

Тут нужно не только 100 грамм, но и справочник по WinAPI

Уточню:
1. тебе нужно только выводить, а вводить не надо.
2. хочеться использовать обычные write/writeln и отображать их вывод на отдельном элементе напоминающем консоль.

Если так, то:

Насчет первого пункта, в качестве такого элемента можно использовать TMemo, а можно TPaintBox, но на нем самостоятельно все отрисовывать, что в общем не сложно. Можно, конечно и свой компонент написать.

Насчет второго пункта:
1. написать класс производный от TStream
2. в нем определить метод Write - он будет получать выводимый текст.
3. подключить модуль streamio из FCL
4. Сделать Assign(output, MyStream), где MyStream - экземпляр твоего класса созданного в п.1
5. Rewrite(output);
Потом можно writeln('Привет мир!');
:wink:
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение bw » 21.05.2007 20:39:47

4. Сделать Assign(output, MyStream), где MyStream - экземпляр твоего класса созданного в п.1
5. Rewrite(output);

Аналогичные действия проделываются системной процедурой SysInitStdIO. Причем текие переменные как Input и Output являются потоконезависимыми и хотя их значения копируются при "дублировании" потока, нужно учесть что для каждого потока будет вызываться SysInitStdIO и эти переменные будут переопределяться. Так что для каждого нового потока необходимо заново ассигновать эти переменные. Так же нужно учитывать, что при завершении потока эти переменные "закрываются", а может и нет, точно не помню.
Смотрите RTL для подробностей.

..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение shade » 21.05.2007 22:31:25

bw писал(а):Так же нужно учитывать, что при завершении потока эти переменные "закрываются", а может и нет, точно не помню.

Закрытие файлов по завершении, миф распространяемый почти всеми (а может и всеми) учебниками. Об input/output/stderr system сам позаботиться, а то, что открываете вы, вы же и должны закрыть.

bw писал(а):Аналогичные действия проделываются системной процедурой SysInitStdIO

Аналогичные, но иные. Я усомнился, в том, что они вызываются для каждого нового потока и проверил - действительно открываются, но другим методом, отличным от обычного Assign/Reset/Rewrite.

Возможно для каких-то систем и нужно открывать файлы стандартного ввода-вывода для каждого потока, но для обычных Assign/Reset/Rewrite этого делать не нужно. Дело в том, что тип Text по сути обычная структура и Assign просто заполняет поля в этой структуре, и соответственно, если вызвать Assign до закрытия файла, то мы просто потеряем файловый дескриптор.

Например,
Код: Выделить всё
uses sysutils;

var f: Text;
begin
  Assign(f, 'output.txt');
  Rewrite(f);
  writeln('Hello world');
  // не закрывая f, создаем новое связывание с тем же файлом
  Assign(f, 'output.txt');
  Rewrite(f); // <- здесь мы получим ошибку, потому что хотим
              // открыть файл который еще заблокирован
  writeln('we never reach this line');
  writeln(f, 'Hello again');
end.
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение bw » 22.05.2007 02:57:28

Про закрытие точно не скажу, по крайне мере это было бы логично, с моей точки зрения.
Аналогичные, но иные. Я усомнился, в том, что они вызываются для каждого нового потока и проверил - действительно открываются, но другим методом, отличным от обычного Assign/Reset/Rewrite.
Как же иным, точно таким же, вызовом SysInitStdIO, а последний что вызывает, зависит только от реализации RTL для конкретной ОС. Вообще нет прямой необходимости вызывать ни одину из этих процедур (тут ты прав), главное инициализировать объекты Text (Input, Output).
Например я это делаю так (в своей реализации SysInitStdIO и системного IO):
Код: Выделить всё
TextRec(f).InOutFunc := @WriteStdout;
TextRec(f).FlushFunc := @WriteStdout;
TextRec(f).CloseFunc := @CloseStdout;

Так же, при завершении программы, я вызываю Close для Input и Output, хотя реализация этих моих потоковых устройств, не требует закрытия, т.е. CloseStdout, например, у меня реализован так:
Код: Выделить всё
procedure CloseStdout(var f: TextRec);
begin
end;

Хотя тут мы говорим об одном и том же.
Но я считаю что закрывать все же нужно. Ты не знаешь какая реализация скрывается за этой структурой.

..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение shade » 22.05.2007 09:55:58

В контексте данной задачи, все это излишне, поправьте если ошибаюсь.

Нам ведь не нужно свою RTL писать, а правильно заюзать имеющуюся - поэтому достаточно просто Assign(output, MyStream); Rewrite(output); В конце для надежности можно сделать Close(output), но в этом нет большой необходимости, т.к. во-1-х мы выводим не на устройство хранения, а на экран, во-2-х RTL сама закроет output при выходе (а если и не закроет - в случае $APPTYPE GUI, то не страшно).

Можно для уверенности не использовать output, а использовать свою переменную, например myout: Text;
Assign(myout, MyStream);
Rewrite(myout);
writeln(myout, 'Hello world');

А в конце сделать Close(myout); MyStream.Free;

Я бы все это дело вынес бы в отдельный юнит и использовал бы секции инициализации/финализации

Код: Выделить всё
initialization
  MyStream := TMyStream.Create;
  Assign(myout, MyStream);
  Rewrite(myout);

finalization
  Close(myout);
  MyStream.Free;

end.


или события OnCreate/OnDestroy окна на котором планируется выводить консоль
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение nagash » 22.05.2007 10:11:18

2 shade
Да, это именно то, что мне нужно. Принцип понятен.


Спасибо всем, буду пытаться разобраться, но все-таки склоняюсь к выводу, что гораздо проще все переписать с нуля под винду, чем лезть в такие дебри, в которых я пока что практически ничего не понимаю)

Да и программка простая слишком, чтобы из-за нее так париться)
http://ifolder.ru/2089926
nagash
новенький
 
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05

Сообщение shade » 22.05.2007 11:09:59

nagash писал(а):Да и программка простая слишком, чтобы из-за нее так париться)

Понятно, тут просто одну формочку на lazarus сделать и никакой консоли не нужно.

А вообще идея задела за живое, может на недельке напишу компонент :D
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение nagash » 22.05.2007 13:45:29

shade писал(а):Понятно, тут просто одну формочку на lazarus сделать и никакой консоли не нужно.

Нема у меня лазаруса) А траф дорогой...

shade писал(а):А вообще идея задела за живое, может на недельке напишу компонент

Отпишись плиз тут, если напишешь. Интересно было бы разобраться.
nagash
новенький
 
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

Рейтинг@Mail.ru