Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Вывести в memo от 00000000 до 11111111


Автор: RaIDeR 21.7.2005, 12:21
Здравствуйте ! Помогите составить алгоритм который выведет
в memo от 0 до 255 в двоичной системе т.е от 00000000 до 11111111.
Как бы это всё зациклить ... просто ручками писать долго smile

Заранее благодарен.

Автор: chaos 21.7.2005, 12:29
вот черкнул тебе программку правда на С(первести думаю не сложно будет тк в ней нет ни чего...)
Код

#include <stdio.h>

void PrintBin(int n)
{
    for (int i = 7; i > -1; i--)
        ((n >> i) & 0x01) ? printf("1") : printf("0");
    printf("\n");
}

int main(int argc, char* argv[])
{
    for (int i = 0; i < 256; i++)
        PrintBin(i);
    return 0;
}



или так еще можно (n & (1 << i))

просьба модераторам не бить за код на С smile

Автор: Girder 21.7.2005, 12:31
Код
procedure TForm1.Button1Click(Sender: TObject);
var b:Byte;
    i:integer;
    s:string;
begin
 s:='00000000';
 for b:=0 to $FF do
  begin
   for i:=0 to 7 do
    if (b and ($80 shr i))>0 then s[i+1]:='1' else s[i+1]:='0';
   Memo1.Lines.Add(s);
  end;
end;

Автор: Poseidon 21.7.2005, 17:19
Код
function IntToBin(Value: integer; Digits: integer): string;
var
  i: integer;
begin
  result := '';
  for i := 0 to Digits - 1 do begin
    if Value and (1 shl i) > 0
      then result := '1' + result
      else result := '0' + result;
  end;
end; 

procedure TForm1.Button1Click(Sender: TObject);
var a, i: Integer;
begin
for i:= 0 to 255 do
  begin
  a:= StrToInt(IntToBin(StrToIntDef(IntToStr(i), 0), 10));
  Memo1.Lines.Add(IntToStr(a));
  end;
end;

Автор: SoWa 21.7.2005, 19:49
А теперь весь этот код впиши в Thread и будешь рад не тормозящей программе.

Автор: Poseidon 21.7.2005, 20:04
SoWa, все ради вас smile
Код
function IntToBin(Value: integer; Digits: integer): string;
var
  i: integer;
begin
  result := '';
  for i := 0 to Digits - 1 do begin
    if Value and (1 shl i) > 0
      then result := '1' + result
      else result := '0' + result;
  end;
end;

procedure MemoAdd;
var a, i: Integer;
begin
for i:= 0 to 255 do
  begin
  a:= StrToInt(IntToBin(StrToIntDef(IntToStr(i), 0), 10));
  Form1.Memo1.Lines.Add(IntToStr(a));
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
h:cardinal;
begin
CreateThread(nil,128,@MemoAdd,self,0,h);
end;


PS. Только у меня и предыдущий код не сильно уж вешал прогу. smile

Автор: RaIDeR 21.7.2005, 21:17
Спасибо всем большое ! smile

Автор: Петрович 22.7.2005, 08:40
Цитата(Poseidon @ 21.7.2005, 21:04)
SoWa, все ради вас ...

Poseidon, да будет Вам известно что VCL не реентерабельна! А посему, подобное использование ее компонентов (Form1.Memo1.Lines.Add(IntToStr(a))) внутри не не основного потока НЕ ДОПУСТИМО! Это приводит к возникновению трудно выявимых ошибок.

Автор: Poseidon 22.7.2005, 12:35
Цитата
Это приводит к возникновению трудно выявимых ошибок.
Трудно не согласится. Но в данном случае, когда код, да и сама опирация, не сложны, такой проблемы нет. В других случаях возможно. Но нужно-ли усложнять код для простого примера?

Автор: Петрович 22.7.2005, 12:49
Цитата(Poseidon @ 22.7.2005, 13:35)
Но нужно-ли усложнять код для простого примера?

Увы, обязательно!
Дело в том, что человек после учебы на "простом" примере, будет переносить такой подход и на сложные примеры, и на реальные программы. А ошибки в мультипоточных приложениях тем и плохи, что у автора на компе это может ввоще ни разу не привести в ошибкам, а у пользователя - нате вам. Но, даже если и у автора будут возникать ошибки, то лишь время от времени. По собственному опытку знаю - ловить такие ошибки крайне тяжело, практически невозможно. Только полным переписыванием программы!
Вот например, сейчас вынужден держать отключенным режим Hyper-Threading у своего компа только лишь потому что автор одиной из программ которой я пользуюсь не позаботился о потокобезопасности кода в своей программе. Вот и происходит что при загрузке он даже ось умудряется поставить ра*ом. Причем, автор не доступен, и отказаться от проги пока не могу smile.


Автор: Poseidon 22.7.2005, 14:36
Петрович, если не лень, приведи пример правильного кода. А то водать так со мной и приключилось:
Цитата
Дело в том, что человек после учебы на "простом" примере, будет переносить такой подход и на сложные примеры, и на реальные программы.
Конечно не всегда, но я пользуюсь этим "ошибочным" вариантом.

Автор: Петрович 22.7.2005, 14:50
Цитата(Poseidon @ 22.7.2005, 15:36)
Петрович, если не лень, приведи пример правильного кода.

Ща некогда. Вечерком постараюсь набросать.

Автор: Marriage 22.7.2005, 15:24
Петрович
Всегда пользовался методом
Код
Synchronize
, если есть обращение к VCL.
Это являеться привильным ?????

Автор: Poseidon 22.7.2005, 15:42
Цитата(Marriage @ 22.7.2005, 15:24)
Это являеться привильным ?????
Лично я думаю является. Т.к.:
Цитата
procedure Synchronize(Method: TThreadMethod);

Этот метод относится к секции protected, т. е. может быть вызван только из потомков TThread.

Delphi предоставляет программисту метод Synchronize для безопасного вызова методов VCL внутри потоков. Во избежание конфликтных ситуаций, метод synchronize дает гарантию, что к каждому объекту VCL одновременно имеет доступ только один поток.



Автор: Poseidon 22.7.2005, 16:04
Вот набросал тут немного. Так правильно?

Код
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure MemoAdd;
  end;

type
  TMyThread = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;


var
  Form1: TForm1;

implementation

{$R *.dfm}
function IntToBin(Value: integer; Digits: integer): string;
var
  i: integer;
begin
  result := '';
  for i := 0 to Digits - 1 do begin
    if Value and (1 shl i) > 0
      then result := '1' + result
      else result := '0' + result;
  end;
end;

procedure TForm1.MemoAdd;
var a, i: Integer;
begin
for i:= 0 to 255 do
  begin
  a:= StrToInt(IntToBin(StrToIntDef(IntToStr(i), 0), 10));
  Memo1.Lines.Add(IntToStr(a));
  end;
end;

procedure TMyThread.Execute;
begin
Synchronize(Form1.MemoAdd)
end;

procedure TForm1.Button1Click(Sender: TObject);
var Thread: TMyThread;
begin
Thread:= TMyThread.Create(False);
end;

end.

Автор: Петрович 26.7.2005, 09:35
Ну вот. Не прошло и полгода как я вернулся smile
Цитата(Poseidon @ 22.7.2005, 17:04)
Вот набросал тут немного. Так правильно?

Нет. Увы, ты совершил довольно распространенную ошибку! Эту ошибку впервые я увидел в статье какого-то горе программиста. Жаль что она была прочитана многими.
Суть ошибки в следующем.
Как указано в описании метода Synchronize, тело метода переданного в качестве параметра, выполняется в контексте основного потока программы. Теперь, если посмотреть твой код, то вся работа выполняется в методе MemoAdd. А он, в свою очередь, и был передан как параметр при вызове Synchronize. Следовательно, вся работа будет выполняться в контексте основного потока. Т.е. весь смысл использования дополнительного потока теряется!
На самом деле, вся трудоемкая работа должна выполняться в Execute. А Synchronize вызываться только для доступа к методам и свойствам VCL-компонентов.
Правильный код будет выглядеть так:
Код

...
function IntToBin (Value: integer; Digits: integer): string;
var
  i: integer;
begin
  result := '';
  for i := 0 to Digits - 1 do begin
    if Value and (1 shl i) > 0
      then result := '1' + result
      else result := '0' + result;
  end;
end;

type
  TMyThread = class(TThread)
  private
    StrForSave :String;       // поле для передачи параметра в SaveStrToMemo
    procedure SaveStrToMemo;  // метод вызываемый в контексте основного потока
  protected
    procedure Execute; override;
  end;

procedure TMyThread.SaveStrToMemo;
begin
  // минимально необходимые действия выполняемые в контексте основного потока
  Form1.Memo1.Lines.Add(StrForSave);
end;

procedure TMyThread.Execute;
var i :Integer;
begin
  FreeOnTerminate := True;        // дабы TMyThread автоматически уничтожился по завершению
  for i:= 0 to 255 do begin
    StrForSave := IntToBin(i,8);
    Synchronize(SaveStrToMemo);
  end;
end;

//---

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyThread.Create(False);
end;


Это правильный метод, рекомендуемый Borland.

Однако, как всегда не единственный.
Например, есть одна интересная особенность процедуры SendMessage. Дело в том, что эта процедура обеспечивает "синхронный" вызов соответствующей оконной процедуры для обработки посылаемого сообщения. А тонкость в том, что вызов оконной процедуры осуществляется в контексте потока создавшего окно, вне зависимости от контекста потока вызвавшего SendMessage. Обеспечивается это самой Windows. Если же знать что все формы Delphi программа создает в контексте основного потока, то этим можно воспользоваться. Вот что мы можем получить в результате:
Код

const
  WM_MY_AddToMemo = WM_USER + 123;

type
  TForm1 = class(TForm)
    ...
  private
    procedure AddToMemoMessage (var Msg: TMessage); message WM_MY_AddToMemo;
  ...
  end;

...

function ThreadFunc (Param: Integer) :Integer; stdcall;
var
  i :Integer;
  s :String;
begin
  for i:= 0 to 255 do begin
    s := IntToBin(i,8);
    SendMessage(Param,WM_MY_AddToMemo,Integer(pChar(s)),0); // СИНХРОННАЯ посылка сообщения форме
  end;
  Result := 0; // код завершения потока. В даннном случае не используется, только лишь для того что бы Delphi не ругался
end;

procedure TForm1.AddToMemoMessage(var Msg: TMessage);
begin
  Memo1.Lines.Add(pChar(Msg.wParam));
end;

procedure TForm1.Button1Click(Sender: TObject);
var 
  h :Cardinal;
  ThreadId :Cardinal;
begin
  h := CreateThread(nil,128,@ThreadFunc,Pointer(Self.Handle),0,ThreadId);
  CloseHandle(h); // нам не нужен результат работы потока, поэтому сразу закроем его хендл
end;

В данном примере я специально не использовал тип tThread дабы продемонстрировать использование потоков через WinAPI.
Обратите внимание на следующее:
1. Функция потока это именно function которая может возвращать результат. Кроме того, она имеет один параметр, и использует способ передачи параметров stdcall
2. Хендл потока возвращаемый CreateThread должен обязательно закрываться как только становится не нужным. Иначе, будут теряться ресурсы системы, естественно в рамках вашего процесса.

В общем, я затронул лишь один из аспектов многопоточных приложений. Белее подробно, рекомендую ознакомиться со статьей: http://mbo88.narod.ru/ToC.html Это просто ОТЛИЧНАЯ статья.


Добавлено @ 09:41
Да, кстати. Совсем забыл. Под Delphi, вместо лучше CreateThread использовать BeginThread

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)