【问题标题】:Delphi local net appDelphi 本地网络应用程序
【发布时间】:2012-10-18 00:04:51
【问题描述】:

尝试学习如何制作服务器-客户端应用程序之类的东西。我试图在所有客户端中绘制圆圈(单击鼠标),所以这就是我尝试这样做的方式。但它不起作用 - 没有错误,但表单是空的。我需要修复什么? 客户端代码

unit Client;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, {Figure, Ball,} IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, ScktComp;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Button1: TButton;
    ClientSocket: TClientSocket;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);



  private

  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  f:boolean;
  p:MyPoint;
  s:MyPoint;
  z:TCanvas;
  obj: MyFigure;
  pX, pY:Integer;
  myBuf: array[1..32] of Integer;
  dataBuf: array[1..32] of Integer;
implementation

{$R *.dfm}



procedure TForm1.FormCreate(Sender: TObject);
begin

  Timer1.Enabled:=false;
  Timer1.Interval:=5;
  z:=Form1.Canvas;//TCanvas.Create;

  Button1.Caption:='Пуск';


  f:=false;

  ClientSocket.Port:=1234;
  ClientSocket.Active:= False;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if not f then
 begin
  Timer1.Enabled:=true;
  Button1.Caption:='Стоп';
  f:=not f;
 end
else
 begin
  Timer1.Enabled:=false;
  Button1.Caption:='Пуск';
  ClientSocket.Active:= True;
  f:=not f;
 end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 //z.Lock;

  //z.Brush.Color:=ClWhite;
  //z.FillRect(Canvas.ClipRect);

  //obj.Draw(z);
  if ClientSocket.Active  then
     ClientSocket.Socket.ReceiveBuf(dataBuf, 32);

  z.Brush.Color:=ClRed; 
  z.Ellipse(dataBuf[1] + 10, dataBuf[2] + 10,dataBuf[1] - 10, dataBuf[2] - 10);

//z.Unlock;
end;



procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
      ClientSocket.Active := false;
end;


procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin

  myBuf[1]:=X;
  myBuf[2]:=Y;
  if ClientSocket.Active  then
     ClientSocket.Socket.SendBuf(myBuf, 32);

end;

end.

服务器

unit ServerProject;

interface

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

type
  TForm1 = class(TForm)
    ServerSocket1: TServerSocket;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientWrite(Sender: TObject;
      Socket: TCustomWinSocket);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  sBufer : array [1..32] of Integer;
implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  ServerSocket1.Port:=1234;
  ServerSocket1.Active := True;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ServerSocket1.Active := false;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  i:integer;

begin
  for i := 0 to ServerSocket1.Socket.ActiveConnections-1 do
  begin
    with ServerSocket1.Socket.Connections[i] do
    begin
      ReceiveBuf(sBufer, 32);
    end;
  end;
end;

procedure TForm1.ServerSocket1ClientWrite(Sender: TObject;
  Socket: TCustomWinSocket);
var
  i:integer;

begin
  for i := 0 to ServerSocket1.Socket.ActiveConnections-1 do
  begin
    with ServerSocket1.Socket.Connections[i] do
    begin
      SendBuf(sBufer, 32);
    end;
  end;

end;

end.

【问题讨论】:

    标签: delphi sockets drawing client-server delphi-7


    【解决方案1】:

    您的绘画代码在错误的位置,并且正在绘画错误的东西。在 Windows 程序中,您需要绘制以响应 WM_PAINT 消息。你没有这样做。更重要的是,您必须在通过调用BeginPaint 提供的设备上下文上进行绘制。

    VCL 为您包装了所有这些细节,但您仍然需要遵守规则。在您的情况下,我建议您在表单中添加一个 TPaintBox 组件。然后为画框实现一个OnPaint 事件处理程序。最后,每当您希望重新绘制绘制框时,例如在计时器上,调用绘制框的Invalidate 方法。

    我怀疑除了先前绘制的椭圆之外,您还希望绘制每个新椭圆。在这种情况下,最好先将它们绘制到屏幕外位图上,然后在绘制到绘图框时,在绘图框上绘制该位图。关键是一个窗口需要能够重新绘制它自己的整体。当您绘制到屏幕设备时,您绘制的内容会在下次需要绘制该窗口时丢失。因此,如果需要,应用程序有责任在任何时候绘制其整个自身。

    更一般地说,我敦促您停止使用全局变量。他们会给你带来无穷无尽的麻烦。尽可能选择局部变量。如果您需要在不同的方法调用之间保持状态,请使用成员变量。指导原则是尽可能使用最窄的范围。

    您当前的设计使用计时器来轮询新数据。这是一个非常糟糕的方法。最有效和最有效的方法是使用同步阻塞通信。 Indy 采用了这种方法。相反,Windows 套接字组件倾向于以异步模式使用。不管这两种方法的相对优点如何,您都不应该对计时器进行轮询。如果您确实使用异步通信,则通过处理事件而不是轮询来响应新数据。

    您的程序目前正在尝试将 GDI 绘画和网络通信混合在一起。我建议您尝试一次掌握这些概念。学习如何在不分心交流的情况下绘画。然后当你画坏了,试着带入交流方面。

    【讨论】:

    • 但如果我在procedure TForm1.FormMouseDown 中写类似z.Ellipse(X + 10, Y + 10, X- 10, Y - 10); 的内容,它会正确绘制椭圆
    • 好吧,我说你需要画画来回复WM_PAINT你不信。
    • 不,我相信你(但实际上我现在并没有正确理解所有事情,我的英语不太好)但据我所知,我在这里所做的只是从服务器发送一些带有数据的客户端数组,然后从服务器发送到该数组的所有客户端。如果像z.Ellipse(X + 10, Y + 10, X- 10, Y - 10); 这样的东西在这里工作(我检查过)为什么不工作z.Ellipse(dataBuf[1] + 10, dataBuf[2] + 10,dataBuf[1] - 10, dataBuf[2] - 10);
    • 我猜dataBuf 不包含您认为它包含的内容。正如我所看到的,您的代码太混乱了,无法取得真正的进展。你需要尝试一次学习一件事。就目前而言,您的代码有太多不同方面的设计不佳,并且这些不同方面的问题会使您的学习和理解尝试混为一谈。首先我会得到正确的绘画代码。
    • 好的。所以通讯不工作。下一步是隔离程序的那部分并找出原因。一次只专注于一个方面。你已经建立了一个大程序,但很多都失败了。你不知道在哪里看。一次构建一个,只有在每个部分都独立运行时才能继续。
    猜你喜欢
    • 1970-01-01
    • 2015-03-24
    • 2021-06-06
    • 2022-09-29
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多