Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » VC++ / MFC » Image mit GDI+

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
24.02.2006, 09:20 Uhr
kleineSchildy



Hallo,

ich habe ein paar Fragen zu dem Thema. Ich habe folgenden Code-Schnipsel


C++:
Gdiplus::Image image(L"test.TIFF");
Gdiplus::Graphics g((m_cPicture.GetDC())->m_hDC);
g.DrawImage(&image,Gdiplus::Point(0,0));




1. Was bedeutet das L bei Image?
2. Ich möchte mein File gern mittels einer Variable laden (wo der Dateiname drinsteht), es will aber einfach nicht funktionieren. Wie macht man es richtig?
3. Das Bild wieder super angezeigt, aber nicht dauerhaft. Bei Popups (oder halt anderen Programmen) die sich über meiner Anwendung öffnen, verschwindet das Bild an dieser Stelle. Wie bekommt man sowas in den Griff?

Viele Grüße
Jana
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
24.02.2006, 10:04 Uhr
Guybrush Threepwood
Gefürchteter Pirat
(Operator)


Das L ist ein Makro das den String in ein anderes Format konvertiert, ich weiß nur gerade nicht welches. Das sollte sich aber leicht rausfinden lassen wenn du in der Doku nachschaust was Image für einen Typen erwartet.


Du musst WM_PAINT abfangen wo das Betriebssystem dir mitteilt das du deine Sachen neu zeichnen musst und das Bild da dann wieder malen. Bei der MFC ist es glaube ich OnPaint
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
24.02.2006, 10:22 Uhr
kleineSchildy



Hallo Guybrush,

kannst du mir das mit WM_PAINT genauer beschreiben?
Ich bin Anfänger. Es reicht nicht, wenn man mir ein paar Brocken hinwirft und ich nicht genau weiß, was ich dann machen soll

Viele Grüße
Jana
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
24.02.2006, 10:39 Uhr
Guybrush Threepwood
Gefürchteter Pirat
(Operator)


Such in deinem Projekt mal ob du irgendwo eine OnPaint Methode deines Fensters hast. Wenn nicht musst du die über den Klassenassistenten hinzufügen.
Jedesmal wenn irgendetwas passiert was dazuführt das dein Fenster neugezeichnet werden muss sendet Windows die Nachricht WM_PAINT an dein Fenster um dir das mitzuteilen. Diese Nachricht kannst du in éinem MFC Programm mit der OnPaint Methode behandeln.

Innerhalb der Methode musst du dann einfach das Bild nochmal malen.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
24.02.2006, 10:44 Uhr
kleineSchildy



so funktioniert es leider nicht, wie mache ich es richtig?


C++:
void CCDSEM_Bild_ViewerDlg::OnPaint()
{
    Gdiplus::Image image(L"test.TIFF");
    Gdiplus::Graphics g((m_cPicture.GetDC())->m_hDC);
    g.DrawImage(&image,Gdiplus::Point(0,0));

    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}


 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
24.02.2006, 10:49 Uhr
Guybrush Threepwood
Gefürchteter Pirat
(Operator)


Zuerstmal solltest du die Rückgabewerte der Funktionen prüfen um auf Fehler reagieren zu können. Wenn keine Fehler auftreten würde ich das mal debuggen und gucken ob er beim Draw was darstellt und das dann aus irgendeinem Grund wieder verschwindet oder ob er gar nicht erst etwas darstellt.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
25.02.2006, 15:15 Uhr
mmc20
puss in boots


hi, das ganze ist etwas unglücklich angeordnet...

du zeichnest ja mit "g.DrawImage()" dein bild, und erst danach schaust du nach ob der dlg minimiert ist ?!
besser ist dein bild irgendwo anders zu laden und ein flag zusetzen ob es gezeichnet werden darf, und dies dann hinter "CDialog::OnPaint()" erledigen, sonst "übermalt" der dialog dein bild wieder.

C++:
// als member
    Gdiplus::Graphics m_meinBild;
    Gdiplus::Image m_image;
    bool m_bBildIstGeladenUndDarfGezeichnetWerden;
...
// im ctor
    m_bBildIstGeladenUndDarfGezeichnetWerden = false;
...
// irgendwo in OnInitDlg
    m_image(L"test.TIFF");
    m_meinBild( (m_cPicture.GetDC())->m_hDC );
    m_bBildIstGeladenUndDarfGezeichnetWerden = true;
...
void CCDSEM_Bild_ViewerDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
        if ( m_bBildIstGeladenUndDarfGezeichnetWerden )
            m_meinBild.DrawImage( &image, Gdiplus::Point(0,0) );
    }
}

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
25.02.2006, 21:55 Uhr
Spacelord
Hoffnungsloser Fall


@mmc20:
Hi,ich hatte heute morgen schon begonnen ne Antwort zu schreiben,wurde dann unterbrochen und hatte den Text dann gespeichert.Sei mir also nicht böse wenn meine Antwort jetzt deinen Beitrag "ignoriert" .

@kleineSchildy:
Hallo,
mit diesem Thread hatte ich gerechnet .
Das Problem dass du schilderst hatte ich dir ja in dem anderen Thread schon angekündigt.
Was ich da gepostet hatte war nunmal die allereinfachste Variante die überhaupt machbar ist.
Damit dein Bild beim Neuzeichnen nicht verschwindet ist,wie Guybrush Threepwood schon geschrieben hat, OnPaint genau der richtige Ort.
OnPaint wird jedesmal aufgerufen wenn ein Bildschirmbereich deines Fensters als ungültig erklärt wurde und neu gezeichnet werden muss.Die Gültigkeit des Zeichenbereichs ist auch eines deiner Probleme.
Ganz grob gesagt(und technisch eigentlich nicht richtig) ruft dein Dialog für all seine Kindfenster(Buttons Statics etc) auch die OnPaint auf.Interessant ist da immer der Teil CPaintDC dc(this). Dahinter verbergen sich WinApi Aufrufe von BeginPaint und EndPaint (EndPaint wird erst im Destruktor von CPaintDC aufgerufen,also nach dem Verlassen von OnPaint)wodurch sich deine Kindelemente neu zeichnen und wieder für gültig erklären.Das Problem ist jetzt halt dass das CStatic Feld dass du als Leinwand nimmst überhaupt nichts von dem Bild weiss das es zeichnen soll!Du benutzt das Staticfeld ja nur indirekt.Der Dialog wird erst nach dem Verlassen von OnPaint,mit den Daten die die Kindfenster und der Dialog geliefert haben,"aktuallisiert"...also werden deine Zeichenbemühungen brutal übermalt .
Damit es überhaupt erstmal funktioniert müsstest du,nachdem du das Bild gezeichnet hast,den Bereich des Statics explizit als gültig erklären.
Eine funktionierende (aber trotzdem schlechte) Variante würde dann so aussehen:

C++:
void CCDSEM_Bild_ViewerDlg::OnPaint()
{
    Gdiplus::Image image(L"test.TIFF");

    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
        CDC* the_dc = m_cPicture.GetDC();
        Gdiplus::Graphics g(the_dc->m_hDC);
        g.DrawImage(&image,Gdiplus::Point(0,0));
        m_cPicture.ReleaseDC(the_dc);
        m_cPicture.ValidateRect(NULL);
    }
}


Diese Lösung ist aber ziemlich übel! Da gehen jedem Programmierer die Nackenhaare hoch wenn so komplexe Objekte wie Bilder lokal angelegt werden und somit bei jedem Betreten von OnPaint angelegt,geladen und beim Verlassen wieder zerstört werden.Das mag bei nem 50KB tiff Bild noch garnichtmal sooo auffallen,aber probier das Gleiche mal mit nem 20MB Bitmap.
Das Problem köntest du umgehen indem Du in deiner Dialogklasse einen Zeiger auf ein Image Objekt als Attribut anlegst und diesem in OnInitDialog mit der statischen Methode Image::FromFile ein Image zuordnest und dieses dann erst im Destruktor des Dialogs wieder löscht.
Auf diese Lösung werde ich aber nicht weiter eingehen weil eine saubere objektorientierte Lösung nur mit unwesentlich mehr Aufwand verbunden ist und die Wiederverwendbarkeit diesen Minimalaufwand rechtfertigt.
Also hier ne kleine Schritt für Schritt Anleitung:
1.Mach nen Rechtsklick und öffne den Klassenassi.
2.Leg ne neue Klasse CPictureStatic an und leite diese von CStatic ab.
3.Leg über die Nachrichtenzuordnungstabelle ne Bearbeitungsfunktion für WM_PAINT an.
4.Deklarier einen Zeiger auf ein Image Objekt als Attribut von CPictureStatic.
5.Initialisier den Zeiger im Konstruktor mit NULL.
6.Setz nen delete auf den Zeiger in den Destruktor .
7.Deklarier ne Methode void SetPicture(wchar_t* path,BOOL B = FALSE)

Der komplette Code der neuen Klasse sieht dann so aus:
Der Header

C++:
class CPictureStatic : public CStatic
{
// Konstruktion
public:
    CPictureStatic();

// Attribute
protected:
    Gdiplus::Image *image;

// Überschreibungen
    // Vom Klassen-Assistenten generierte virtuelle Funktionsüberschreibungen
    //{{AFX_VIRTUAL(CPictureStatic)
    //}}AFX_VIRTUAL

// Implementierung
public:
    void SetPicture(wchar_t* path,BOOL b = FALSE);
    virtual ~CPictureStatic();

    // Generierte Nachrichtenzuordnungsfunktionen
protected:
    //{{AFX_MSG(CPictureStatic)
    afx_msg void OnPaint();
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};



Die Implementierung:

C++:
#include "stdafx.h"
#include "PictureStatic.h"
//weitere projektbezogene includes

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPictureStatic

CPictureStatic::CPictureStatic()
{
    image = NULL;
}

CPictureStatic::~CPictureStatic()
{
    delete image;
}

BEGIN_MESSAGE_MAP(CPictureStatic, CStatic)
    //{{AFX_MSG_MAP(CPictureStatic)
    ON_WM_PAINT()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// Behandlungsroutinen für Nachrichten CPictureStatic

void CPictureStatic::OnPaint()
{
    CPaintDC dc(this);
    
    if(image != NULL)
    {
        Gdiplus::Graphics g(dc.m_hDC);
        g.DrawImage(image,Gdiplus::Point(0,0));
    }
}

void CPictureStatic::SetPicture(wchar_t* path,BOOL b)
{
    delete image;
    image = Gdiplus::Image::FromFile(path,b);
}



Jetzt musst du nur noch den Header in deine Dialogklasse inkludieren und dem Static,dem du ja ne Controlvariable vom Typ CStatic zugewiesen hattest, ne neue vom Typ CPictureStatic zuweisen.

Dann noch in OnInitDialog

C++:
     m_cPicture.SetPicture(L"PfadZuDeinemBild.tiff");


und feddich....

Ab jetzt sorgt das Staticfeld selber dafür dass bei Bedarf alles neu gezeichnet wird und du musst in der OnPaint von deinem Dialog garnicht mehr rumfummeln.

Und das Beste ist dass du in dem nächsten Projekt,wo du nen Bild anzeigen willst,nur noch die beiden Dateien einfügen musst,ne Variable anlegst und diese(eventuell über SubclassDlgItem) einem Staticfeld zuordnest.
Dann noch mit SetPicture nen Bild festlegen und dann war es das.
Damit bist du in Zukunft mit 2-3 Zeilen Code in der Lage nen "beliebiges" Bild anzuzeigen

MfG Spacelord
--
.....Ich mach jetzt nämlich mein Jodeldiplom.Dann hab ich endlich was Eigenes.

Dieser Post wurde am 25.02.2006 um 21:59 Uhr von Spacelord editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
02.03.2006, 09:05 Uhr
kleineSchildy



Hallo,

erstmal vielen Dank für eure Hilfe. Es funktioniert jetzt, aber noch nicht so, wie ich es mir wünsche. Da muß ich noch ein bißchen basteln. Aber nochmal mein zweites Problem:


C++:
Gdiplus::Image image(L"test.TIFF");
Gdiplus::Graphics g((m_cPicture.GetDC())->m_hDC);
g.DrawImage(&image,Gdiplus::Point(0,0));



Wie muß ich den Code umändern, damit ich kein festes Bild lade, sondern aus einer Variable? Ich habe jetzt schon viel in der Hilfe geschaut und auch bei Google, aber für C++ einfach nichts passendes gefunden. Die Variable ist vom Typ CString.


Viele Grüße
Jana
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
02.03.2006, 09:57 Uhr
kleineSchildy



So müßte es ja rein theoretisch gehen:


C++:
Gdiplus::Image* image;
image->FromFile(sPicture, FALSE);
Gdiplus::Graphics g((m_cPicture.GetDC())->m_hDC);
g.DrawImage(image,Gdiplus::Point(0,0));



Aber es kommt immer diese Fehlermeldung


Code:

:...Bild_ViewerDlg.cpp(291) : error C2664: 'FromFile' : cannot convert parameter 1 from 'class CString' to 'const unsigned short *'
        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Error executing cl.exe.



Aber warum um Himmels Willen, sollte der Pfad ne Zahl sein???
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ VC++ / MFC ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: