Я новичок в MFC и пытаюсь изучить его с проектом диалоговой базы MFC на VS2008. Вот архивы, которые я сделал:
Во-первых, мне удалось отобразить список изображений из папки в элемент управления Listbox. После этого я также обработал событие click в каждой строке списка, чтобы загрузить и показать изображение в Picture Control (тип Bitmap) с правой стороны. Вы можете увидеть изображение ниже для легкого понимания: Пожалуйста, нажмите здесь для изображения моего диалога MFC
Вот код Заметка m_ListCtrl
а также static_picture
переменные списка и элемента управления изображением:
void CMyClientDlg::OnLbnSelchangeList1(){
CString imagePath;
m_ListCtrl.GetText(m_ListCtrl.GetCurSel(),imagePath);
CImage picture;
picture.Load(imagePath);
if (!picture.IsNull())
{
float screenWidth = 200, screenHeight = 200;
float imageWidth = picture.GetWidth();
float imageHeight = picture.GetHeight();
//scaling:
float pictureRatio = imageWidth/ imageHeight;
float newImageWidth;
float newImageHeight;
int aligmentX = 0;
int aligmentY = 0;
if (pictureRatio <= 1)
{
newImageWidth = imageWidth*(screenHeight/imageHeight);
newImageHeight = screenHeight;
aligmentX = (screenWidth-newImageWidth)/2;
}
else
{
newImageWidth = screenWidth;
newImageHeight = imageHeight*(screenWidth/imageWidth);
aligmentY = (screenHeight - newImageHeight)/2;
}
//end scaling.
CDC *screenDC = GetDC();
CDC mDC;
mDC.CreateCompatibleDC(screenDC);
CBitmap bitMap;
bitMap.CreateCompatibleBitmap(screenDC, screenWidth, screenHeight);
CBitmap *pob = mDC.SelectObject(&bitMap);
mDC.SetStretchBltMode(HALFTONE);
picture.StretchBlt(mDC.m_hDC, aligmentX, aligmentY, newImageWidth, newImageHeight, 0, 0, imageWidth, imageHeight, SRCCOPY);
mDC.SelectObject(pob);
/*.......code to convert bitmap to BYTE* ........*/
/*.......code to send BYTE* over socket........*/
//display the bit map
static_picture.SetBitmap((HBITMAP)bitMap.Detach());
//clean up
ReleaseDC(screenDC);
}
}
Теперь я хотел бы продвинуться еще на один шаг и попытаться работать с сокетом … и да, я успешно отправил и получил простой символ * или CString поверх сокета.
То, что я хочу сделать: вместо того, чтобы показывать изображение в этом диалоговом окне, оно показывает изображение в другом диалоговом окне (на сервере).
Каким-то образом я узнал, что есть две функции, которые хорошо работают SetBitmapBits()
а также GetBitmapBits()
(Честно говоря, я только что прочитал это на каком-то источнике и не имею ни малейшего представления, подходят ли они здесь для моей цели).
Итак, я добавил этот кусок кода, чтобы превратить вышеуказанное растровое изображение в массив BYTE bmpBuffer
:
BITMAP bmpProperties;
bitMap.GetBitmap(&bmpProperties);
int bmpDemension = bmpProperties.bmWidthBytes*bmpProperties.bmHeight;
BYTE* bmpBuffer=(BYTE*)GlobalAlloc(GPTR, bmpDemension);
bitMap.GetBitmapBits(bmpDemension,bmpBuffer);
Затем отправьте этот массив через сокет:
UpdateData(TRUE);
char *socketBuffer = reinterpret_cast<char*>(bmpBuffer);
send(m_ClientSocket, socketBuffer, sizeof(socketBuffer), 0);
//clean up after send
GlobalFree((HGLOBAL)bmpBuffer);
На другом диалоге. Примечание. Я жестко запрограммировал размерность растрового изображения на 160000, чтобы упростить задачу:
void CMyServer2Dlg::OnReceive(){
char *socketBuffer = new char [1025];
int iLen;
iLen = recv(m_sConnected, socketBuffer, 1025, NULL);
if(iLen==SOCKET_ERROR)
{
AfxMessageBox("Could not Receive");
}
else
{
BYTE* bmpBuffer = reinterpret_cast<BYTE*>(socketBuffer);
//re-construct the bitmap
CBitmap clone;
CDC *screenDC = GetDC();
CDC mDC;
mDC.CreateCompatibleDC(screenDC);
clone.CreateCompatibleBitmap(screenDC, 200, 200);
clone.SetBitmapBits(160000,bmpBuffer);
//Picture control(type bitmap) has variable "static_picture"static_picture.SetBitmap((HBITMAP)clone.Detach());
UpdateData(FALSE);
ReleaseDC(screenDC);
GlobalFree((HGLOBAL)bmpBuffer);
}
delete socketBuffer;
И это просто не работает … Скажите, пожалуйста, где я все испортил? И извините за длинный пост …..
Я думаю, что наиболее вероятной причиной является то, что ваш приемник не получает все данные изображения. Я предлагаю вам при отправке указать размер растрового изображения в пакет, чтобы получатель получил правильный размер.
Вот пример кода. Имейте в виду, что они просто для демонстрации идеи, вам может понадобиться отладка, чтобы убедиться, что они работают.
Шаг 1: Упакуйте размер растрового изображения. Я предполагаю, что здесь размер меньше 64 КБ, поэтому используется int. Если размер может быть больше, чем 64 КБ, вы можете использовать INT64.
int bmpDemension = bmpProperties.bmWidthBytes*bmpProperties.bmHeight;
int bufferSize = bmpDemension + sizeof(int);
BYTE* bmpBuffer=(BYTE*)GlobalAlloc(GPTR, bufferSize );
bitMap.GetBitmapBits(bmpDemension,bmpBuffer + sizeof(int));
memcpy(bmpBuffer, &bmpDemension, sizeof(int)); // put the size into the head of package.
шаг 2: отправить его
Имейте в виду, я использую здесь bufferSize, потому что sizeof (bmpBuffer) возвращает размер указателя, который равен 4, а не размер пространства.
UpdateData(TRUE);
char *socketBuffer = reinterpret_cast<char*>(bmpBuffer);
send(m_ClientSocket, socketBuffer, bufferSize , 0);
//clean up after send
GlobalFree((HGLOBAL)bmpBuffer);
На стороне получателя:
Сначала вы читаете размер растрового изображения, а затем получаете в соответствии с размером данных.
void CMyServer2Dlg::OnReceive(){
char socketBuffer[1025];
int iLen;
iLen = recv(m_sConnected, socketBuffer, sizeof(int), NULL); //read the bigmap size
if(iLen==SOCKET_ERROR)
{
AfxMessageBox("Could not Receive");
}
else
{
int dimension = *((int *) socketBuffer);
char * bitmapBuffer = new char[dimension];
int readSize = dimension;
char * pBuffer = bitmapBuffer;
while (readSize > 0)
{
int sizeToRead = readSize > sizeof(socketBuffer) ? sizeof(socketBuffer) : readSize;
iLen = recv(m_sConnected, socketBuffer, sizeToRead , NULL);
memcpy(pBuffer, socketBuffer, iLen);
pBuffer += iLen;
readSize -= iLen;
}
// when the loop done, you shall have all data in bitmapBuffer.
....
// I leave the remaining code to you.
Опять же, этот код просто для демонстрации идеи.
Других решений пока нет …