Доброго времени суток.
Это продолжение статьи, в котором я расскажу о создании клиента для моего чата.
Клиентской части мною было уделено гораздо больше времени серверной, так как здесь есть вторая важная составляющая — графическая часть.
Дизайн клиента очень простой, даже примитивный. Я не видел смысла создавать меню бар в приложении. На форме размещены 2 панели, одна из них меняет цвет, если клиент подключен к серверу она зеленая, иначе — красная. На следующей панели размещен TabControl. Я перепробовал 5 или 6 вариантов дизайна приложения, и самым удобным нашел использование компонента TabControl. В его вкладки заносятся имена пользователей находящихся в сети, при выборе соответствующей вкладки начинается переписка с этим пользователем(также выводится история сообщений). Сообщения выводятся в компонент Memo, писать сообщения надо в компонент Edit, отправка- по нажатию соответствующей кнопки или клавише Enter.
У клиента также реализовано сворачивание окна в область уведомлений.
При поступлении нового сообщения воспроизводится приятный звук.
За всю работу с сетью отвечает стандартный компонент ClientSocket. Клиент, также как и сервер, принимая сообщения первым делом отделяет от них первые 4 символа. Затем определяется что делать дальше. Все происходит в событии OnRead.
Код 4796 значит что клиенту следует отправить свое имя для «регистрации» на сервере.
7788 — один из самых главных кодов, он ставится в начале входящего сообщения. При этом отделяется имя отправителя и само сообщения. Далее идет проверка на состояние окна клиента. Если открыта вкладка с диалогом отправителя сообщения то сообщение просто добавляется в новую строку Memo, в начале добавляется время поступления сообщения. Если открыта вкладка переписки с другим пользователем, воспроизводится звук и во вкладке с нужным пользователем после имени добавляется надпись "+1". При переходе в эту вкладку надпись убирается. Если окно приложения свернуто то выплывает контекстное меню с двумя вариантами: закрыть меню и перейти к переписке. Меню вызывается на всех компьютерах в одинаковом месте — правом верхнем углу. Для этого определяется разрешение монитора. В любом из случаев сообщение вместе со временем поступления вносится в файл. Для каждого пользователя есть свой файл переписки, из него же берется история переписки.
8714 — значит, что пора обновить список пользователей в TabControl.
В одной папке с приложением обязательно должен храниться файл конфигурации( с чисто символическим расширением ".config", потом сделаю нормальный INI-файл). В файле три строчки: имя клиента, ip-адрес сервера и версия приложения. При запуске приложения все это извлекается из файлы и используется по назначению.
Мне удалось разработать примитивную, но все таки очень работоспособную программу позволяющуюпоболтать на рабочем месте связать несколько десятков компьютеров в офисе и прекратить общение с помощью телефонных звонков или тем более хождения по офису.
У меня появились кое-какие идеи, которые в будущем будут реализованы, например добавление графического чата, возможности пересылки файлов, может быть голосовой чат. Все это, конечно же надо реализовывать не с помощью билдера 2006 года. Проект, например я уже перенес в Embarcadero RAD Studio XE8, очень уж нужна была версия на мак.
На этом думаю все, самое важное я написал. Очень надеюсь что данная статья будет полезна для начинающих работать в C++ Builder. Все исходники и сама программа тут.
P.S. Первую часть статьи заминусовали, но первый опыт написания статей мне очень понравился. Комментируйте, буду исправлять свои ошибки. Спасибо за уделенное внимание!
Это продолжение статьи, в котором я расскажу о создании клиента для моего чата.
Клиентской части мною было уделено гораздо больше времени серверной, так как здесь есть вторая важная составляющая — графическая часть.
Дизайн клиента очень простой, даже примитивный. Я не видел смысла создавать меню бар в приложении. На форме размещены 2 панели, одна из них меняет цвет, если клиент подключен к серверу она зеленая, иначе — красная. На следующей панели размещен TabControl. Я перепробовал 5 или 6 вариантов дизайна приложения, и самым удобным нашел использование компонента TabControl. В его вкладки заносятся имена пользователей находящихся в сети, при выборе соответствующей вкладки начинается переписка с этим пользователем(также выводится история сообщений). Сообщения выводятся в компонент Memo, писать сообщения надо в компонент Edit, отправка- по нажатию соответствующей кнопки или клавише Enter.
У клиента также реализовано сворачивание окна в область уведомлений.
void __fastcall TFormMain::DrawItem(TMessage& Msg)
{
IconDrawItem((LPDRAWITEMSTRUCT)Msg.LParam);
TForm::Dispatch(&Msg);
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::MyNotify(TMessage& Msg)
{
POINT MousePos;
switch(Msg.LParam)
{
case WM_RBUTTONUP:
if (GetCursorPos(&MousePos))
{
PopupMenu1->PopupComponent = FormMain;
SetForegroundWindow(Handle);
PopupMenu1->Popup(MousePos.x, MousePos.y);
}
else
Show();
break;
case WM_LBUTTONDBLCLK:
Show();
break;
default:
break;
}
TForm::Dispatch(&Msg);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
bool __fastcall TFormMain::TrayMessage(DWORD dwMessage)
{
NOTIFYICONDATA tnd;
PSTR pszTip;
pszTip = TipText();
tnd.cbSize = sizeof(NOTIFYICONDATA);
tnd.hWnd = Handle;
tnd.uID = IDC_MYICON;
tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
tnd.uCallbackMessage = MYWM_NOTIFY;
if (dwMessage == NIM_MODIFY)
{
tnd.hIcon = (HICON)IconHandle();
if (pszTip)
lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip));
else
tnd.szTip[0] = '\0';
}
else
{
tnd.hIcon = NULL;
tnd.szTip[0] = '\0';
}
return (Shell_NotifyIcon(dwMessage, &tnd));
}
//---------------------------------------------------------------------------
HICON __fastcall TFormMain::IconHandle(void)
{
return (Image2->Picture->Icon->Handle);
}
//---------------------------------------------------------------------------
PSTR __fastcall TFormMain::TipText(void)
{
return ("Office Chat");
}
//---------------------------------------------------------------------------
LRESULT IconDrawItem(LPDRAWITEMSTRUCT lpdi)
{
return 0;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TFormMain::FormDestroy(TObject *Sender)
{
TrayMessage(NIM_DELETE);
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::N1Click(TObject *Sender)
{
Show();
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::N2Click(TObject *Sender)
{
Application->Terminate();
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::FormCloseQuery(TObject *Sender, bool &CanClose)
{
CanClose=false;
FormMain->Hide();
}
//---------------------------------------------------------------------------
При поступлении нового сообщения воспроизводится приятный звук.
За всю работу с сетью отвечает стандартный компонент ClientSocket. Клиент, также как и сервер, принимая сообщения первым делом отделяет от них первые 4 символа. Затем определяется что делать дальше. Все происходит в событии OnRead.
Код 4796 значит что клиенту следует отправить свое имя для «регистрации» на сервере.
7788 — один из самых главных кодов, он ставится в начале входящего сообщения. При этом отделяется имя отправителя и само сообщения. Далее идет проверка на состояние окна клиента. Если открыта вкладка с диалогом отправителя сообщения то сообщение просто добавляется в новую строку Memo, в начале добавляется время поступления сообщения. Если открыта вкладка переписки с другим пользователем, воспроизводится звук и во вкладке с нужным пользователем после имени добавляется надпись "+1". При переходе в эту вкладку надпись убирается. Если окно приложения свернуто то выплывает контекстное меню с двумя вариантами: закрыть меню и перейти к переписке. Меню вызывается на всех компьютерах в одинаковом месте — правом верхнем углу. Для этого определяется разрешение монитора. В любом из случаев сообщение вместе со временем поступления вносится в файл. Для каждого пользователя есть свой файл переписки, из него же берется история переписки.
8714 — значит, что пора обновить список пользователей в TabControl.
void __fastcall TForm1::ClientSocketRead(TObject *Sender,
TCustomWinSocket *Socket)
{
AnsiString str=Now().CurrentDateTime();
message=Socket->ReceiveText();
AnsiString recieveText=message;
AnsiString Text=recieveText;
if(message.SubString(1,4).AnsiCompare("4796")==0)
{
ClientSocket->Socket->SendText("6141"+myname);
}
else if(message.SubString(1,4).AnsiCompare("7788")==0)
{
if(TabControl1->Tabs->operator [](TabControl1->TabIndex).AnsiCompare(message.SubString(5,message.Pos(":")-5))==0)
{
ListBox->Lines->Add(str+" "+message.SubString(5,message.Length()));
file(message.SubString(5,message.Pos(":")-5),message.SubString(message.Pos(":")+1,message.Length()),Now().CurrentDateTime(),"in");
PlaySound("message.wav",0,SND_ASYNC);
PopupMenu2->PopupComponent = Form1;
PopupMenu2->Popup(GetSystemMetrics(SM_CXSCREEN)-200, 20);
}
else if(TabControl1->Tabs->operator [](TabControl1->TabIndex).AnsiCompare(message.SubString(5,message.Pos(":")-5))!=0)
{
PlaySound("message.wav",0,SND_ASYNC);
AnsiString im;
AnsiString mess;
im=message.SubString(5,message.Pos(":")-5);
mess=message.SubString(message.Pos(":")+1,message.Length());
file(im,mess,Now().CurrentDateTime(),"in");
AnsiString name=message.SubString(5,message.Pos(":")-5);
active=TabControl1->TabIndex;
count=TabControl1->Tabs->Count;
AnsiString n;
TabControl1->Tabs->Clear();
for(int i=0;i<count;i++)
{
n=m[i];
if(n.AnsiCompare(name)!=0)
TabControl1->Tabs->Add(n);
else if(n.AnsiCompare(name)==0)
TabControl1->Tabs->Add(n+"+1");
}
}
}
else if(message.SubString(1,4).AnsiCompare("8714")==0)
{
TabControl1->Tabs->Clear();
AnsiString str=message.SubString(5,message.Length());
const char separator[]=",";
int i=0;
char *Ptr=NULL;
Ptr=strtok(str.c_str(),separator);
while (Ptr)
{
//if(myname.AnsiCompare(Ptr)!=0)
TabControl1->Tabs->Add(Ptr);
strcpy(m[i],Ptr);
Ptr=strtok(0,separator);
i++;
}
}
}
В одной папке с приложением обязательно должен храниться файл конфигурации( с чисто символическим расширением ".config", потом сделаю нормальный INI-файл). В файле три строчки: имя клиента, ip-адрес сервера и версия приложения. При запуске приложения все это извлекается из файлы и используется по назначению.
Итог
Мне удалось разработать примитивную, но все таки очень работоспособную программу позволяющую
У меня появились кое-какие идеи, которые в будущем будут реализованы, например добавление графического чата, возможности пересылки файлов, может быть голосовой чат. Все это, конечно же надо реализовывать не с помощью билдера 2006 года. Проект, например я уже перенес в Embarcadero RAD Studio XE8, очень уж нужна была версия на мак.
На этом думаю все, самое важное я написал. Очень надеюсь что данная статья будет полезна для начинающих работать в C++ Builder. Все исходники и сама программа тут.
P.S. Первую часть статьи заминусовали, но первый опыт написания статей мне очень понравился. Комментируйте, буду исправлять свои ошибки. Спасибо за уделенное внимание!