Отправляет email-рассылки с помощью сервиса Sendsay

Инвестирование с нуля

  Все выпуски  

Программирование на Си и С++ с нуля 145) Полезные компоненты


Школа программирования

145) Программирование на С++: полезные компоненты

Письма.

1. Как можно посмотреть время выполнения отдельной команды или цикла в режиме отладки?

Время можно померять программно - с помощью функции GetTickCount. Для этого придется дополнять исходный код:

   long t;
   t = GetTickCount(); // текущее время
   ... // группа команд, время которой меряем
   t = GetTickCount() - t; // сколько прошло, в миллисекундах

2. В режиме отладки той программы которая дана в рассылке 142):

    int m[10];
      int i;
      for( i=1; i<=10; i++ )
        if( i<5) m[i] = 1;
        else m[i] = 2;

Что Вы имеете в виду под словами при работе возникает ошибка? Ведь программа продалжает работать.

В том то и дело, что ошибка есть - она возникла во время работы, однако программа продолжает функционировать (хотя так не всегда может быть). Это основная опасность программ на С++ - вроде бы она не "падает", и в то же время выполняет некорректные операции. Поэтому разработчику трудно понять, есть ли ошибка, или ее нету.

Сообщений об ошибке не выдаёт.
...
При запуске программы в поле отображения (рис2) видим, что программа обратилась к несуществующему элементу внутри массива и записала кокие-то данные. Повидимому число "15809404" по адресу находилось сразу после девятого элемента в свободной от массива "m" памяти. Правильно ли работает программа, что обращается к несуществующему массиву или программа должна была выдать сообщение об ошибке?

Конечно, неправильно - но язык С++ не проверяет выходы за границы массива, поэтому программа фактически обращается за пределы своего адресного пространства. Скорее всего ошибка на один элемент к явному нарушению не приведет (может быть, в памяти следом за массивом располагается какая-нибудь переменная - вот ее значение и будет тайно модифицировано :), но если адресуемый элемент отстоит далеко от начала массива, скорее всего возникнет типичная ошибка Windows "программа выполнила недопустимую операцию".

Письмо от Андрея Кузнецова.

5. На форме с полем ввода и кнопкой после ввода текста в поле ввода для нажатия на кнопку приходится кликать по ней мышкой или нажимать клавиши Tab и Enter. Как сделать, чтобы кнопка срабатывала после ввода текста в поле ввода только по нажатию клавиши Enter (минуя клавишу Tab)?
Можно отслеживать нажатия клавиш на уровне поля ввода (событие OnKeyUp, как Вы и упоминали), и в случае нажатия пользователем на клавишу Enter (константа Билдера - VK_RETURN) прямо вызывать обработчик события нажатия на кнопку программы из обработчика события поля ввода. Если поле ввода MessageEdit, а кнопка названа SubmitButton, то это может выглядеть так:

  //---------------------------------------------------------------------------
  void __fastcall TMainForm::SubmitButtonClick(TObject *Sender)
  {
      ShowMessage(MessageEdit->Text);
  }
  //---------------------------------------------------------------------------
  void __fastcall TMainForm::MessageEditKeyUp(TObject *Sender, WORD
  &Key,
        TShiftState Shift)
  {
      if( Key == VK_RETURN) SubmitButtonClick(Sender);
  }
  //---------------------------------------------------------------------------

Разумеется, обработчик события нажатия на кнопку должен быть написан до обработчика события нажатия на клавишу над полем ввода.
А лучше (красивее) воспользоваться компонентом диспетчерезации событий ActionList Билдера. В кроссплатформенном программировании создание главного окна приложения начинается с createActions(), даже если там всего один пункт меню "Выход"... :)
Есть и ещё способы, но и этих хватит...
Если бы программисты делали автомобили, то ими можно было бы управлять с помощью правого руля, левого руля, джойстика, клавиатуры, а также имелись бы ручки для любителей толкать машину сзади... :)

Для интересующихся трюками с кнопками в Билдере на сайте Beginа есть статья:
Программный "щелчок" по кнопке в Borland C++ Builder
http://www.prog-begin.net.ru/modules.php?name=News&file=article&sid=39&mode=&order=0&thold=0

В Вашей книге встретил название программы Workshop, для просмотра файлов dll. Если Вас не затруднит - полное скажите название - а то в сети очень много программ с таким именем :)
По-видимому, имеется в виду программа Resource Workshop, которую можно использовать для извлечения изображений из файлов программ (*.exe) и динамически присоединяемых библиотек (*.dll). В Интернете её искать не нужно, поскольку она входит в состав дистрибутивов Borland C++ Builder с 1 по 6-ю версии (про Турбо не знаю). По умолчанию она, правда, не устанавливается, но процесс её установки, а также работы с ней, включая юридические последствия этого ;) , подробно описан в Вашей книге (Бобровский С.И. Самоучитель программирования на языке C++ в системе Borland C++ Builder 4.0. - М.: ДЕСС INFORCOM PRESS, 1999) на страницах 182-183, куда бы и переадресовал всех интересующихся. Впрочем, несложно написать и собственную программу для извлечения пиктограмм (icons) из экзешек и длл'ок. Как пример могу рекомендовать исходный код моей программы - IconExtractor (Извлекатель пиктограмм). Среда разработки: Borland C++ Builder 5. Программа извлекает изображения из *.exe и *.dll файлов и сохраняет в виде пиктограмм (icons). Написана для демонстрации работы WinAPI функции ExtractIcon. Код здесь:

http://www.prog-begin.net.ru/modules.php?name=Files&go=view_file&lid=2

Спрашивают, как создать свою функцию - эту важную тему рассмотрим в следующем уроке.

Вот письмо с примером правильного (настойчивого :-) подхода к составлению алгоритма, программированию и отладке:

Спешу поделиться своей радостью!!! Хух, я все-таки нашел ее!!! ОШИБКУ. Пока не было новых выпусков рассылки решил напрячь мозги и попробовать отсортировать массив другим способом. Потратил на это всю неделю, но так и не успел до прихода следующего выпуска рассылки. Решил все-таки добить это дело, поэтому рассылку просмотрел мельком и не стал разбирать варианты решения "одноклассников".
АЛГОРИТМ 1 (по убыванию)
Выдумался поначалу такой алгоритм.
1. Находим максимальное (max) значение массива X и его индекс (imax);
2. Делаем его первым (нулевым) в другом массиве Y;
3. На место максимального значения X[imax] загоняем -1 (любое значение меньшее минимального было бы правильнее), но т.к. у меня массив был заполнен значениями от 0 до 999, то я выбрал -1;
Ну и так далее в цикле
4. Выводим массив на экран в Memo-поле.

АЛГОРИТМ 2 (тоже по убыванию)
В процессе реализации первого алгоритма родился второй. Более красивый и без другого массива, но суть обоих алгоритмов похожа.
1. Находим максимальное (max) значение массива X и его индекс (imax);
2. Меняем нулевой член массива с максимальным;
3. Далее снова находим максимум, но уже не с нулевого члена массива, а с 1-ого, т.к. нулевым у нас и так уже максимальное значение. Т.е. находим второе по величине значение массива и ставим его на второе место. Ну и т.д.
4. Выводим массив на экран в Memo-поле.

Решил сложить все, как из кубиков, т.к. нахождение максимума (1 кубик) и вывод массива на экран (2 кубик) у меня уже было реализовано в предыдущем задании, оставалось сделать только замены.

Кубики сложил, запускаю, а не тут-то было. В обоих случаях массив сортировался до какого-то момента, а потом: в алгоритме 1 все время выскакивали "-1", а в алгоритме 2 сортировка была неправильной, но только с какого-то момента. Времени у в будние дни было мало, но и то, что я тратил меня уже начинало раздражать:))). В 100-ый или 300-ый раз я впивался в текст программы, менял местами и то и это. Все никак. Дым шел из ушей:) Но вот в субботу с утречка я ЕЕ нашел!!! Ошибка оказалась настолько ничтожной, что аж стыдно. Кстати, меня сбило именно то, что когда я делал первое задание (тобишь нахождение максимума и минимума и их индексов) все работало. Работало только потому, что массив был достаточно большой (100 значений) и вероятность того, что нулевой член массива будет максимумом или минимумом была 1/100. В общем ошибка была в том, что я не задал начальное значение максимального индекса, т.е. не написал маленькую строчку в начале цикла:
imax = 0;
Я вас уж, наверное, утомил всей этой ерундой, но для меня это важно, что я ее все-таки добил:)))
ВОТ ОНИ МОИ АЛГОРИТМИКИ РЕАЛИЗОВАННЫЕ НА C++
Я тут опустил заполнение массива. Изначально массив int x[100] заполняется случайными числами от 0 до 999.
АЛГОРИТМ 1

  int x[100];
  int y[100];
  int i, j, max, imax;

  {
  for ( int j = 0; j < 100; j++ ) {

  max = x[0];
  imax = 0;
  for ( i = 1; i < 100; i++ ) {
    if ( max < x[i] ) {
      max = x[i];
      imax = i;
      }
    }

  y[j] = max;
  x[imax] = -1;
  }

  Memo3->Text = "";
  for ( j = 0; j < 100; j++ )
  Memo3->Text = Memo3->Text + y[j] + " ";
  }

  АЛГОРИТМ 2
  int x[100];
  int i, j, a, max, imax;

  {
  for ( j = 0; j < 100; j++ ) {

  max = x[j];
  imax = j; // ЗЛОСЧАСТНАЯ ОШИБКА
  for ( i = j+1; i < 100; i++ ) {
    if ( max < x[i] ) {
      max = x[i];
      imax = i;
      }
    }

  a = x[j];
  x[j] = max;
  x[imax] = a;
  }

  Memo2->Text = "";
  for ( j = 0; j < 100; j++ )
  Memo2->Text = Memo2->Text + x[j] + " ";
  }

Хочу еще раз сказать большое спасибо за рассылку, бо еще лет 10 и мой мозг ушел бы в такое глубокое подполье, что никакое ГЕСТАПО его оттуда, никаким Макаром бы не вытянуло:)))
Артем

Полученные знания по программированию можно уже применять, очевидно, для реализации множества других задач. Главное, чтобы быстрее стать хорошим программистом, надо писать как можно больше кода. Брать задачки, например, с олимпиад (если удалось запрограммировать сортировку, то и олимпиада по плечу :) - просто времени конечно больше потребуется, но это уже дело наживное).
Но при этом иногда возникают непредвиденные проблемы. Вот например:

Столкнулся с проблемой - решал задачу про Сету - создателя шахмат. Про вознаграждение - на первую клетку одно зерно, на вторую два и т.д.
тридцать первый эл массива = 1073741824
32-й = выходит за пределы диапазона и имеет отрицательное значение и с 33-го выводятся нули.
64-й эл-т это число в котором тридцать восемь разрядов - можно в С++ решать такие задачи?
Как записать, что бы не быть привязанным к диапазону значений?
Константин.

Увы, С++ для подобных задач слабо подходит. Но попробуйте объявить тип не int, а unsigned __int64:

unsigned __int64 моя-переменная ;

Он 64-разрядный, и должен охватывать числа от 0 до 1234567887654321 (но только положительные!).


Компоненты панели Standard

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

Почти все компоненты имеют свойства Width и Height - ширина и высота, а также Left и Top (левая и верхняя координаты положения объекта на форме). Свойство Enabled делает объект доступным для взаимодействия, а если в нем записано значение false, то такой объект будет виден, но заблокирован. Свойство Visible делает объект видимым, а если в нем записано значение false, то такой объект в работающей программе будет невидим (в проектировщике он конечно останется видимым). Часто используется свойство Color (цвет), а также Font (настройки шрифта, которым делаются надписи на объекте).

Панель Standard.

Кнопка TButton. Свойство Caption - надпись на кнопке. Событие OnClick - реакция программы на нажатие кнопки.

Поле-метка TLabel. Свойство Сaption - отображаемая строка.

Поле ввода TEdit. Свойство Text - отображаемая строка и вводимый человеком текст.

Меню TMainMenu. Сложный компонент, для которого имеется визуальный проектировщик меню. Для каждого пункта меню свойство Сaption - его название, а событие OnClick - реакция программы на выбор этого пункта.

Многострочное поле ввода TMemo. Отображаемые и вводимые пользователем строки представлены в свойстве Lines. У него есть подсвойство Strings, к которому можно обращаться как к массиву строк:

  Memo1->Lines->Strings[5]

Флажок TCheckBox. Свойство Checked логического типа определяет, включен флажок или нет. Событие OnClick - реакция программы на переключение флажка (уже после того, как флажок был переключен). Свойство Caption - выводимый рядом с флажком текст.

Список TListBox. Показывает список строк, в котором можно выделять отдельные строки. Строки хранятся в свойстве Items, доступны в виде массива через свойство Items (такое же, как и Lines компонента TMemo). Новые строки добавляются методом Add:

  ListBox1->Items->Add("новая строка");

Удаляеются - методом Delete с номером удаляемого элемента:

  ListBox1->Items->Delete(3);

Индекс текущего выделенного объекта хранится в свойстве ItemIndex. Если в нем записано значение -1 , то считается, что ни одна строка не выделена.

По умолчанию строки показываются в том порядке, в каком они добавлялись в список. Если в свойство Sorted занести значение true, то список будет автоматически упорядочивать свое содержимое.

Полоса прокрутки TScrollBar. Используется для прокрутки содержимого сторонних объектов, или как индикатор положения ползунка. Крайнему левому положению ползунка соответствует значение, заданное в свойстве Min, крайне правому - значение свойства Max. Текущее положение ползунка определяется значением свойства Position. Когда пользователь протаскивает ползунок, генерируется событие OnScroll.

Группа переключателей TRadioGroup. Предназначена для организации набора переключателей - в некоторый момент времени может быть выбран только один из них. Когда выбирается новый переключатель, выделение с прежнего переключателя снимаетеся. Данный компонент представляет одновременно целую группу переключателей. Текущий выбранный переключатель задается свойством ItemIndex (если ничего не выбрано, его значением будет -1). Сами переключатели задаются своими названиями в свойстве Items (массив строк). В это свойство с помощью встроенного редактора вводится набор строк - например:

кошка
мышка
собачка

Таким образом в группе созданы три переключателя с соответствующими названиями.

Декоративная панель TPanel, никаких действий не выполняющая. Она используется для группировки разных элементов управления в одном месте. Панель вместе с входящими в нее элементами можно целиком перемещать, а если ее сделать невидимой через свойство Visible, то невидимыми станут и входящие в нее объекты. Таким образом можно делать многоэкранный интерфейс в рамках одной формы - одну панель с нужным набором элементов делаем видимым, а остальные временно скрываем - за границами формы и с помощью свойства Visible.

Другие группы компонентов рассмотрим в следующих выпусках.


(c) 2004-2006 Сергей Бобровский bobrovsky as russianenterprisesolutions.com

Школа программирования с нуля
Все предыдущие выпуски базового курса всегда тут:
http://www.infiltration.ru/p/

Неофициальный сайт поддержки (со срочными вопросами - сюда):
www.prog-begin.net.ru.


Вышел мой учебный курс "Технологии Delphi. Разработка приложений для бизнеса".
http://shop.piter.com/book/978591180282/

Учебный курс рассчитан не только на разработчиков, но и на всех тех, кто хочет стать ИТ-менеджером. Для этого как минимум нужно иметь общее представление о современных технологиях разработки и их истории и владеть соответствующей терминологией.
В книге описаны десятки технологий, каждой из которых посвящены отдельные книги. Таким образом, купив одну мою книгу, вы существенно сэкономите :) В книге полностью описан язык Delphi (версия 2006, полностью совместимая с Turbo Delphi) для обеих платформ - Win32 и .NET. Охвачены также темы работы с файлами на этих платформах, создания файл-серверных, клиент-серверных, распределенных приложений, веб-программ (Indy, ASP.NET, веб-сервисы). Описаны языки SQL и OCL. Немало глав посвящены истории программирования и различных технологий. Особое внимание уделено созданию программ с помощью технологии ECO и языка моделирования UML - программы фактически рисуются, и теперь даже для создания корпоративных приложений и их переноса в Интернет не обязательно знать программирование!
Отдельная часть отведена технологиям организации групповой работы, управления требованиями, контроля версий, локализации и тестирования.
Тут подробнее про книгу.

Другие мои книги, которые пока доступны в продаже:


Дизайн рассылки: Алексей Голубев - Web-дизайн и web-программирование


В избранное