Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.74/81: Рейтинг темы: голосов - 81, средняя оценка - 4.74
13 / 13 / 2
Регистрация: 06.01.2009
Сообщений: 70
1

Ссылки (гиперссылки) + картинки в RichEdit

15.08.2009, 21:01. Показов 14614. Ответов 40
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Как в RichEdit сделать так, что бы при клике на ссылки он на них переходил?
Тут нашел как включить это дело http://cppbuilder.ru/articles/0129.php , разобрался с включением распознавания, но не разобрался пока как сделать чтоб он реагировал на ссылки. И можно ли не только текст сделать гиперссылкой, но и картинку? Тогда еще один вопрос: как вставить картинку?

Добавлено через 1 час 32 минуты 20 секунд
Тыкс, с тем как сделать чтоб реагировало на любые упоминания url-ссылок разобрался (запускается через браузер по умолчанию). Вот код:
Unit1.h:
C++
1
2
3
4
...
public:     
        void __fastcall TForm1::WndProc(Messages::TMessage &Message);
...
Unit1.cpp:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
   unsigned mask = SendMessage(RichEdit1->Handle, EM_GETEVENTMASK, 0, 0);
   SendMessage(RichEdit1->Handle, EM_SETEVENTMASK, 0, mask | ENM_LINK);
   SendMessage(RichEdit1->Handle, EM_AUTOURLDETECT, true, 0);
   RichEdit1->Text = " http://google.ru" ;
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
   if(Message.Msg == WM_NOTIFY){
      if(((LPNMHDR)Message.LParam)->code == EN_LINK){
         ENLINK* p = (ENLINK *)Message.LParam;
         if(p->msg == WM_LBUTTONDOWN){
            SendMessage(Form1->RichEdit1->Handle, EM_EXSETSEL, 0, (LPARAM)&(p->chrg));
            ShellExecute(Form1->Handle, "open", Form1->RichEdit1->SelText.c_str(), 0, 0, SW_SHOWNORMAL);
         }
      }
   }
   TForm::WndProc(Message);
}
Но еще остались вопросы про картинки.
1
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.08.2009, 21:01
Ответы с готовыми решениями:

Гиперссылки в RichEdit
Не можете мне пожалуйста помочь, я искал информацию об этом и нашол как можно сделать гиперссылку...

Ссылки, гиперссылки Excel
У нас есть таблица в Excel, в ней указаны идентификаторы, все уникальные без повторов. Возможно ли...

Извлечение гиперссылки из картинки
Здравствуйте, специалистам и всем помощникам ;) Я не специалист по написанию Макросов, но решил...

Изменение цвета рамки картинки-гиперссылки при наведении курсора.
Изменение цвета рамки картинки-гиперссылки при наведении курсора.Никак не могу этого...

40
Программист TH
292 / 147 / 12
Регистрация: 06.01.2009
Сообщений: 537
01.11.2009, 12:30 21
Author24 — интернет-сервис помощи студентам
Вот оно, а перед этим - работа с OLE-объектами в RichEdit. У мен они сохр - 2 года потратил на изучение етого компонента и создание текстовых редакторов )))) Кстати тот сайт не работает, но... делаю новый портал, ждём... Итс был немного флуд, извен
Вложения
Тип файла: zip richeditrc_src.zip (2.9 Кб, 158 просмотров)
1
говнокодер
1273 / 297 / 35
Регистрация: 31.10.2009
Сообщений: 1,432
01.11.2009, 14:42 22
Во первых строках поста моего объявляются всяческие благодарности и спасибости 2 DanUnited, респект и уважуха!=)

во вторых:
Цитата Сообщение от Jnis Посмотреть сообщение
АКТИВНЫЕ ВОПРОСЫ:
Как вставить картинку в RichEdit?
ответ:
Тестовая прога: Включаем в проект файлы которые лежат в архиве DanUnited :

https://www.cyberforum.ru/atta... 1257067120

, кидаем на форму RichEdit (это у нас будет RichEdit1), далее такой код:

h-file:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//---------------------------------------------------------------------------
 
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <RichEditOLE.h>
#include <RichEditOleCallback.h>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TRichEdit *RichEdit1;
private:    // User declarations
public:     // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
cpp - file:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//---------------------------------------------------------------------------
 
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
new TIRichEditOle(RichEdit1);
}
//---------------------------------------------------------------------------
компилируем.
Для тестирования я открыл Paint, уменьшил холст до размера смайла, начеркал калямалю, ctrl+A, ctrl+C и ctrl+V в RichEdit в нашей проге. Вуаля=)
1
говнокодер
1273 / 297 / 35
Регистрация: 31.10.2009
Сообщений: 1,432
01.11.2009, 14:52 23
Вот кстати скомпилированый проект (тестовый - из пейнта картинки мона втыкать)
если я где-то ошибся...
Вложения
Тип файла: rar redit.rar (691.7 Кб, 157 просмотров)
0
говнокодер
1273 / 297 / 35
Регистрация: 31.10.2009
Сообщений: 1,432
18.11.2009, 18:12 24
Лучший ответ Сообщение было отмечено как решение

Решение

Короче, как вставить смайл, кто знает как проще - ваше Щастье... можете - поделитесь. Лично для меня смайлы в RichEdit вставлять - очень большой йеморой, поэтому я делюсь этим, пусть не совершенным, пусть замороченным, но все же рабочим алгоритмом... в инете ничего путевого не нагуглил, но, уважаемые модераторы, этот вопрос является ИМО часто задаваемым.. поэтому обратите пожалста на сие внимание, если вас не затруднит.

Для начала стоит отметить, что я пишу чат для локальной сети, и поэтому у меня обрабатывается Received Text - полученный текст... Я выдвинул идею, что смайлы необходимо заменять специальными выражениями (в приведенном ниже примере это $sm1$, $sm2$, $sm3$, $sm4$), а при отображении полученного сообщения, заменять эти выражения, на изображения смайла. Для удобства, я повесил на форму RichEdit1 и Memo1, причем Memo1 - невидимое (Visible=false) - куда добавляется весь текст, полученный, отправленный и т.п. RichEdit служит только для отображения и ни одного обработчика события для него нет... работаем только с Memo.

Принцип такой:
Когда текст в Memo меняется,
1 - мы определяем позицию (номер символа в строке) каждой команды, заносим её в соответствующий массив (для каждого смайла отдельный), удаляем команду (это в цикле)

2 - присваем полученный текст (без команд) RichEdit'у

3 - в цикле, вставляем изображения смайлов, в позиции взятые из массивов.

Пример: тут я взял 4 смайла (можно больше можно меньше... принцип все равно один), идентификаторы: $sm1$, $sm2$, $sm3$, $sm4$.

Исходник

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
void __fastcall TForm1::Memo1Change(TObject *Sender)//на изменение в мемо
{
AnsiString SM;
AnsiString ClpData;
int m2l = Memo1->Text.Length();
int *sp = new int[m2l]; //под каждый смайл создаем массив с размерностью в длину текста в мемо
int *sp2 = new int[m2l];
int *sp3 = new int[m2l];
int *sp4 = new int[m2l];
int cp;
unsigned DataHandle;
HPALETTE APalette;
Word  Format;
 
for (int i=0; i<m2l; i++)
{
sp[i]=NULL; //обнуляем значения (иначе прога ведет себя некорректно
sp2[i]=NULL;
sp3[i]=NULL;
sp4[i]=NULL;
}
 
SM=Memo1->Lines->Text; //заносим в AnsiString SM  текст  из Memo, с этим мы и будем работать
 
for (int i=0; i<m2l;)
{
cp=SM.Pos("$sm"); //определяем положение "общей части"
if (cp!=0) //если вхождение присутствует
  {
        if (SM.SubString(cp,5)=="$sm1$")//определяем что за смайл
        {
        SM.Delete(cp, 5);//удаляем спец. выражение
        sp[i]=cp;//заносим в соот. массив позицию смайла (номер символа, где должен быть смайл в строке)
        cp=NULL;//обнуляем переменную
        i++;//цикл продолжается
        }
        else if (SM.SubString(cp,5)=="$sm2$")//если первого смайла нету проверяем наличие второго
        {
        SM.Delete(cp, 5);
        sp2[i]=cp;
        cp=NULL;
        i++;
        }
        else if (SM.SubString(cp,5)=="$sm3$")// и так далее
        {
        SM.Delete(cp, 5);
        sp3[i]=cp;
        cp=NULL;
        i++;
        }
        else if (SM.SubString(cp,5)=="$sm4$")
        {
        SM.Delete(cp, 5);
        sp4[i]=cp;
        cp=NULL;
        i++;
        }
        else//если есть просто $sm хз че делать, в моем примере придется запретить юзеру
        //вводить сивол $, но для себя я придумаю другой спец символ...
        {
        i++;//правда тут можно еще с бубном поплясать
        }
 
  }
else//если вхождения $sm необнаружено завершаем цикл
        {
        i=m2l;
        }
}
RichEdit1->Text=SM;//присваем RichEdit'у модифицированый текст (без команд)
for (int i=0; i<m2l;)
{
if (sp[i]!=0||sp[i]!=NULL)//если элемент массива с данным номером имеет значение отличное от нуля
        {
        RichEdit1->SelStart=sp[i]+(i-1);//устанавливаем каретку в RichEdit'е на позицию куда надо воткнуть смайл
        //(так надо ибо командау нас из 5-и символов, а смайл как 1, и происходит смещение - долго бился головой ап стену - помогло)
        ClpData = Clipboard()->AsText; //тут проблема, т.к. вставить пикчу можно только через буфер обмена, другого пути не нашел
        //поэтому приходится "спасать" пользовательские данные и то часть... стратегический план в разработке...
        Image2->Picture->Bitmap->SaveToClipboardFormat(Format,DataHandle,APalette);//картинку в БО
        Clipboard()->SetAsHandle(Format,DataHandle);
        RichEdit1->PasteFromClipboard();//вставляем картинку
        RichEdit1->SelStart=sp[i]+1;//устанавлием каретку после смайла
        Clipboard()->AsText = ClpData;// возвращаем в буфер текст
        i++;//продолжаем цикл
        }
else if (sp2[i]!=0||sp2[i]!=NULL)//аналогично
        {
        RichEdit1->SelStart=sp2[i]+(i-1);
        ClpData = Clipboard()->AsText;
        Image3->Picture->Bitmap->SaveToClipboardFormat(Format,DataHandle,APalette);
        Clipboard()->SetAsHandle(Format,DataHandle);
        RichEdit1->PasteFromClipboard();
        RichEdit1->SelStart=sp2[i]+1;
        Clipboard()->AsText = ClpData;
        i++;
        }
else if (sp3[i]!=0||sp3[i]!=NULL)
        {
        RichEdit1->SelStart=sp3[i]+(i-1);
        ClpData = Clipboard()->AsText;
        Image4->Picture->Bitmap->SaveToClipboardFormat(Format,DataHandle,APalette);
        Clipboard()->SetAsHandle(Format,DataHandle);
        RichEdit1->PasteFromClipboard();
        RichEdit1->SelStart=sp3[i]+1;
        Clipboard()->AsText = ClpData;
        i++;
        }
else if (sp4[i]!=0||sp4[i]!=NULL)
        {
        RichEdit1->SelStart=sp4[i]+(i-1);
        ClpData = Clipboard()->AsText;
        Image5->Picture->Bitmap->SaveToClipboardFormat(Format,DataHandle,APalette);
        Clipboard()->SetAsHandle(Format,DataHandle);
        RichEdit1->PasteFromClipboard();
        RichEdit1->SelStart=sp4[i]+1;
        Clipboard()->AsText = ClpData;
        i++;
        }
else i=m2l; //в противном случае завершаем цикл
}
delete sp; //удаляем массивы
delete sp2;
delete sp3;
delete sp4;
//аффтар этого дикого алгоритма некто аццкий сотона sh4°_°ff ©2009
}


до этого необходимо добавить к проекту файлы в архиве от DanUnited (автор - некто Robert Dunn) (дублирую на всякий случай, архив приложен ниже), и прописать:

C++
1
2
3
4
#include <RichEditOLE.h>
#include <RichEditOleCallback.h>
 
new TIRichEditOle(RichEdit1);
(см также посты выше).

з.ы.: как вариант попробовать переписать сам класс TIRichEditOle из архива, но это оказалось мне не по зубам... в общем вот... вдруг кому да поможет.
Вложения
Тип файла: zip RichEditOle.zip (11.9 Кб, 112 просмотров)
5
1 / 1 / 0
Регистрация: 06.01.2011
Сообщений: 24
03.04.2011, 14:44 25
Спасибо sh4d°_°ff работает! Только для таких как я начинающих и познающих - если вы пробуете вставку картинок таким способом и билдер ругается (ошибку точно не помню но вроде ругался на незарегестрированную функцию) то войдите в опции проекта-директории- и добавьте путь (Include patch и Library patch) к папкам где лежат cpp и h файлы которые вы скачали от тов. sh4d°_°ff. У меня только после этих действий заработало. Спасибо sh4d°_°ff.
0
говнокодер
1273 / 297 / 35
Регистрация: 31.10.2009
Сообщений: 1,432
03.04.2011, 16:29 26
рад что кому-то принесло пользу, сам долго долго бился над этой задачей.
0
UeArtemis
18 / 18 / 3
Регистрация: 23.09.2011
Сообщений: 205
21.02.2013, 11:58 27
Нашел в спецификации формата RTF пример кода с картинкой:
{\pict\wbitmap0\picw170\pich77\wbmbitspixel1\wbmplanes1\wbmwidthbytes22
\picwgoal505
\pichgoal221
\picscalex172
\picscaley172
49f2000000000273023d1101a030
3901000a000000000273023d98
0048000200000275
02040000200010275023e000000000
273023d000002b90002b90002
b90002b90002b9
0002b90002b90002b90002b90002b90002
b92222b90002b90002b90
002b90002b9
0002b90002b90002b90002b9000
Вставил это в файл, открыл его WordPad'ом - страшненькая картинка на месте. Открыл своей программой с RichEdit'ом - ничего.
RichEdit точно поддерживает изображения?
0
говнокодер
1273 / 297 / 35
Регистрация: 31.10.2009
Сообщений: 1,432
21.02.2013, 14:47 28
richedit точно не поддерживает изображения сейчас глядя на всю эту пляску с бубном вокруг richedit ole нахожу куда более оптимальным решением скачать/купить компонент который таки поддерживает картинки.
0
UeArtemis
18 / 18 / 3
Регистрация: 23.09.2011
Сообщений: 205
21.02.2013, 15:20 29
Наткнулся на упоминание RxRichEdit. Что это такое? Где взять?
0
LK
Заблокирован
21.02.2013, 15:56 30
1. TRichEdit не поддерживает изображения.
2. RxRichEdit
0
UeArtemis
18 / 18 / 3
Регистрация: 23.09.2011
Сообщений: 205
27.03.2013, 11:07 31
Цитата Сообщение от LK Посмотреть сообщение
1. TRichEdit не поддерживает изображения.
2. RxRichEdit
Нашел на другом форуме:
RxLib уже лет 5 как умер и что-бы скомпилить его под Builder 2007 - надо ОЧЕНЬ много поработать.
Авторы RxLib уже давно развивают альтернативный пакет компонентов JVCL в котором есть ВСЕ что было в RxLib плюс много нового... Ну и естественно есть версия под Builder 2007.
Где можно почитать про этот JVCL и скачать его?
0
LK
Заблокирован
27.03.2013, 19:41 32
JVCL всегда были на партнерском диске билдера.
0
UeArtemis
18 / 18 / 3
Регистрация: 23.09.2011
Сообщений: 205
28.03.2013, 10:22 33
Нету диска =\
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
28.03.2013, 17:00 34
Блин а что никто не пробовал напрямую через WinApi RICHEDIT 3.0 и его потом юзать ?
1
UeArtemis
18 / 18 / 3
Регистрация: 23.09.2011
Сообщений: 205
28.03.2013, 17:02 35
Гениально!!!
0
UeArtemis
18 / 18 / 3
Регистрация: 23.09.2011
Сообщений: 205
09.06.2016, 15:16 36
Тут пример полностью рабочий, но я не понимаю, как это адаптировать под свою программу: http://www.sources.ru/cpp/cpp_... edit.shtml

Добавлено через 1 час 0 минут
Попытался просто запузырить в свою программу на RAS Studio эти 2 файла. Не компилируется
C++
1
static void InsertBitmap(IRichEditOle *pRichEditOle, HBITMAP hBitmap);
Для начала это ему не нравится.
[bcc32 Error] Unit2.cpp(13): E2147 'IRichEditOle' cannot start a parameter declaration
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.06.2016, 15:32 37
Как вариант используйте html- формат и TCppBrowser для его отображения.

Касательно указанного примера по ссылке там код с использованием MFC, не для C++Builder.
0
UeArtemis
18 / 18 / 3
Регистрация: 23.09.2011
Сообщений: 205
09.06.2016, 15:44 38
Это понятное дело. Просто пример этого парня (ссылка на англ. вариант http://www.codeguru.com/cpp/co... ontrol.htm ) позволяет сохранить картинку прямо внутрь как "\wmetafile". Ну, и открыть и просмотреть соответственно. Если кто поймёт, как переделать под современную RAD Studio - скажите.
0
UeArtemis
18 / 18 / 3
Регистрация: 23.09.2011
Сообщений: 205
23.06.2016, 14:18 39
Цитата Сообщение от sh4d°_°ff Посмотреть сообщение
Во первых строках поста моего объявляются всяческие благодарности и спасибости 2 DanUnited, респект и уважуха!=)

во вторых:


ответ:
Тестовая прога: Включаем в проект файлы которые лежат в архиве DanUnited :

https://www.cyberforum.ru/atta... 1257067120

, кидаем на форму RichEdit (это у нас будет RichEdit1), далее такой код:

h-file:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//---------------------------------------------------------------------------
 
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <RichEditOLE.h>
#include <RichEditOleCallback.h>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TRichEdit *RichEdit1;
private:    // User declarations
public:     // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
cpp - file:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//---------------------------------------------------------------------------
 
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
new TIRichEditOle(RichEdit1);
}
//---------------------------------------------------------------------------
компилируем.
Для тестирования я открыл Paint, уменьшил холст до размера смайла, начеркал калямалю, ctrl+A, ctrl+C и ctrl+V в RichEdit в нашей проге. Вуаля=)
RichEditOLE.h и RichEditOleCallback.h просто необходимые вещи! Большое спасибо. Странно, что админы не закрепили это решение в топе тем.

Я доделал вставку картинок (для метафайлов, т.к. только они адекватно отображаются потом во всех текстовых процессорах).

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
bool TIRichEditOle::InsertMetaFile(HENHMETAFILE hMF)
{
    HRESULT hr;
 
    //Create structured storage.
    LPLOCKBYTES pLockBytes = NULL;
    hr = CreateILockBytesOnHGlobal(NULL, TRUE, &pLockBytes);
    if (FAILED(hr))
        return FALSE;
 
    LPSTORAGE pStorage;
    hr = StgCreateDocfileOnILockBytes(pLockBytes,
           STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE,
           0, &pStorage);
    if (FAILED(hr))
        return FALSE;
 
    TIMFObject *pods = new TIMFObject;
    LPDATAOBJECT lpDataObject;
    hr = pods->QueryInterface(IID_IDataObject, (void **)&lpDataObject);
    if (FAILED(hr))
        return FALSE;
 
    pods->SetMetaFile(hMF);
 
    //Get a pointer to the display site.
    LPOLECLIENTSITE pClientSite;
    hr = FIRichEditOle->GetClientSite(&pClientSite);
    if (FAILED(hr))
        return FALSE;
 
    LPOLEOBJECT pObject;
    CLSID clsid = CLSID_NULL;
 
    //Get the IOleObject interface to the object.
    pObject = pods->GetOleObject(pClientSite, pStorage);
 
    //To ensure that references are counted correctly, notify the object that it is contained.
    OleSetContainedObject(pObject, TRUE);
 
    //Set up object info.
    REOBJECT reobject = { sizeof(REOBJECT)};
    hr = pObject->GetUserClassID(&clsid);
    if (FAILED(hr))
    {
        pObject->Release();
        return FALSE;
    }
 
    reobject.clsid = clsid;
    reobject.cp = REO_CP_SELECTION;
    reobject.dvaspect = DVASPECT_CONTENT;
    reobject.dwFlags = REO_GETMETAFILE; //REO_RESIZABLE | REO_BELOWBASELINE;
    reobject.dwUser = 0;
    reobject.poleobj = pObject;
    reobject.polesite = pClientSite;
    reobject.pstg = pStorage;
    SIZEL sizel = { 0 };
    reobject.sizel = sizel;
 
    //Insert the object.
    hr = FIRichEditOle->InsertObject(&reobject);
 
    //Clean up.
    pods->Release();
    pObject->Release();
    lpDataObject->Release();
    pClientSite->Release();
    pStorage->Release();
    //FIRichEditOle->Release();
    if (FAILED(hr))
        return FALSE;
    else
        return TRUE;
}
//---------------------------------------------------------------------------
void TIMFObject::SetMetaFile(HENHMETAFILE hMF)
{
    FORMATETC formatEtc;
    formatEtc.cfFormat = CF_ENHMETAFILE;    // Clipboard format - MetaFile
    formatEtc.ptd = NULL;                   // Target Device - Screen
    formatEtc.dwAspect = DVASPECT_CONTENT;  // Level of detail - Full content
    formatEtc.lindex = -1;                  // Index - Not applicaple
    formatEtc.tymed = TYMED_ENHMF;          // Storage medium - HMETAFILE handle
 
    STGMEDIUM stgm;
    stgm.tymed = TYMED_ENHMF;               // Storage medium - HMETAFILE handle
    stgm.hEnhMetaFile=hMF;
    stgm.pUnkForRelease = NULL;             // Use ReleaseStgMedium
 
    this->SetData(&formatEtc, &stgm, true);
}
//---------------------------------------------------------------------------
IOleObject *TIMFObject::GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage)
{
    SCODE sc;
    IOleObject *pOleObject;
    sc = ::OleCreateStaticFromData(this, IID_IOleObject, OLERENDER_FORMAT,
            &m_fromat, pOleClientSite, pStorage, (void **)&pOleObject);
 
    return pOleObject;
}
//---------------------------------------------------------------------------
Самое сложное было создать IDataObject.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
class TIMFObject : IDataObject
{
public:
    //static void InsertMetaFile(HENHMETAFILE hMF);
private:
    ULONG   m_ulRefCnt;
    BOOL    m_bRelease;
 
    // The data being bassed to the richedit
    //
    STGMEDIUM m_stgmed;
    FORMATETC m_fromat;
 
public:
    TIMFObject() : m_ulRefCnt(0)
    {
        m_bRelease = FALSE;
    }
    ~TIMFObject()
    {
        if (m_bRelease)
            ::ReleaseStgMedium(&m_stgmed);
    }
    // Methods of the IUnknown interface
    STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
    {
        if (iid == IID_IUnknown || iid == IID_IDataObject)
        {
            *ppvObject = this;
            AddRef();
            return S_OK;
        }
        else
            return E_NOINTERFACE;
    }
    STDMETHOD_(ULONG, AddRef)(void)
    {
        m_ulRefCnt++;
        return m_ulRefCnt;
    }
    STDMETHOD_(ULONG, Release)(void)
    {
        if (--m_ulRefCnt == 0)
        {
            delete this;
        }
 
        return m_ulRefCnt;
    }
    // Methods of the IDataObject Interface
    STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
    {
        HANDLE hDst;
        hDst = ::OleDuplicateData(m_stgmed.hEnhMetaFile, CF_ENHMETAFILE, NULL);
        if (hDst == NULL)
        {
            return E_HANDLE;
        }
 
        pmedium->tymed = TYMED_ENHMF;
        pmedium->hEnhMetaFile = (HENHMETAFILE)hDst;
        pmedium->pUnkForRelease = NULL;
 
        return S_OK;
    }
    STDMETHOD(GetDataHere)(FORMATETC* pformatetc, STGMEDIUM*  pmedium )
    {
        return E_NOTIMPL;
    }
    STDMETHOD(QueryGetData)(FORMATETC*  pformatetc )
    {
        return E_NOTIMPL;
    }
    STDMETHOD(GetCanonicalFormatEtc)(FORMATETC*  pformatectIn ,FORMATETC* pformatetcOut )
    {
        return E_NOTIMPL;
    }
    STDMETHOD(SetData)(FORMATETC* pformatetc , STGMEDIUM*  pmedium , BOOL  fRelease )
    {
        m_fromat = *pformatetc;
        m_stgmed = *pmedium;
 
        return S_OK;
    }
    STDMETHOD(EnumFormatEtc)(DWORD  dwDirection , IEnumFORMATETC**  ppenumFormatEtc )
    {
        return E_NOTIMPL;
    }
    STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
    {
        return E_NOTIMPL;
    }
    STDMETHOD(DUnadvise)(DWORD dwConnection)
    {
        return E_NOTIMPL;
    }
    STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise)
    {
        return E_NOTIMPL;
    }
    // Some Other helper functions
    void SetMetaFile(HENHMETAFILE hMF);
    IOleObject *GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage);
};
//------------------------------------------------------------------------------
Добавлено через 5 минут
То есть теперь влепить картинку можно так:
C++
1
2
TIRichEditOle *RichEditOle1 = new TIRichEditOle(RichEdit1);
RichEditOle1->InsertMetaFile((HENHMETAFILE)MetaFile1->Handle);
Всё Вот он легендарный RichEdit с картинками Без сторонних компонентов.

Добавлено через 2 часа 7 минут
Блин, рано обрадовался. Обнаружились косяки при сохранении: сохраняет только первые 56 байт рисунка.
Это размер структуры REOBJECT, как я понимаю. Почему так? В примере с Bitmap'ом, с которого я копировал, всё работает.

Добавлено через 36 минут
Для Bitmap 100% рабочее. Тут картинка сохраняется полностью.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
bool TIRichEditOle::InsertBitmap(HBITMAP hBitmap) //Моя функция
{
    CImageDataObject::InsertBitmap(FIRichEditOle, hBitmap);
}
 
//////////////////////////////////////////////////////////////////////
// Static member functions
//////////////////////////////////////////////////////////////////////
 
void CImageDataObject::InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap)
{
    SCODE sc;
 
    // Get the image data object
    //
    CImageDataObject *pods = new CImageDataObject;
    LPDATAOBJECT lpDataObject;
    pods->QueryInterface(IID_IDataObject, (void **)&lpDataObject);
 
    pods->SetBitmap(hBitmap);
 
    // Get the RichEdit container site
    //
    IOleClientSite *pOleClientSite;
    pRichEditOle->GetClientSite(&pOleClientSite);
 
    // Initialize a Storage Object
    //
    IStorage *pStorage;
 
    LPLOCKBYTES lpLockBytes = NULL;
    sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
 
    //if (sc != S_OK)
    //  AfxThrowOleException(sc);
    //ASSERT(lpLockBytes != NULL);
 
    sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
        STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &pStorage);
 
    //if (sc != S_OK)
    //{
    //  VERIFY(lpLockBytes->Release() == 0);
    //  lpLockBytes = NULL;
    //  AfxThrowOleException(sc);
    //}
    //ASSERT(pStorage != NULL);
 
    // The final ole object which will be inserted in the richedit control
    //
    IOleObject *pOleObject;
    pOleObject = pods->GetOleObject(pOleClientSite, pStorage);
 
    // all items are "contained" -- this makes our reference to this object
    //  weak -- which is needed for links to embedding silent update.
    OleSetContainedObject(pOleObject, TRUE);
 
    // Now Add the object to the RichEdit
    //
    REOBJECT reobject;
    ZeroMemory(&reobject, sizeof(REOBJECT));
    reobject.cbStruct = sizeof(REOBJECT);
 
    CLSID clsid;
    sc = pOleObject->GetUserClassID(&clsid);
 
    //if (sc != S_OK)
    //  AfxThrowOleException(sc);
 
    reobject.clsid = clsid;
    reobject.cp = REO_CP_SELECTION;
    reobject.dvaspect = DVASPECT_CONTENT;
    reobject.poleobj = pOleObject;
    reobject.polesite = pOleClientSite;
    reobject.pstg = pStorage;
 
    // Insert the bitmap at the current location in the richedit control
    //
    pRichEditOle->InsertObject(&reobject);
 
    // Release all unnecessary interfaces
    //
    pOleObject->Release();
    pOleClientSite->Release();
    pStorage->Release();
    lpDataObject->Release();
}
 
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
 
void CImageDataObject::SetBitmap(HBITMAP hBitmap)
{
    //ASSERT(hBitmap);
 
    STGMEDIUM stgm;
    stgm.tymed = TYMED_GDI;                 // Storage medium = HBITMAP handle
    stgm.hBitmap = hBitmap;
    stgm.pUnkForRelease = NULL;             // Use ReleaseStgMedium
 
    FORMATETC fm;
    fm.cfFormat = CF_BITMAP;                // Clipboard format = CF_BITMAP
    fm.ptd = NULL;                          // Target Device = Screen
    fm.dwAspect = DVASPECT_CONTENT;         // Level of detail = Full content
    fm.lindex = -1;                         // Index = Not applicaple
    fm.tymed = TYMED_GDI;                   // Storage medium = HBITMAP handle
 
    this->SetData(&fm, &stgm, TRUE);
}
//---------------------------------------------------------------------------
IOleObject *CImageDataObject::GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage)
{
    //ASSERT(m_stgmed.hBitmap);
 
    SCODE sc;
    IOleObject *pOleObject;
    sc = ::OleCreateStaticFromData(this, IID_IOleObject, OLERENDER_FORMAT,
            &m_fromat, pOleClientSite, pStorage, (void **)&pOleObject);
 
    //if (sc != S_OK)
    //  AfxThrowOleException(sc);
 
    return pOleObject;
}
//---------------------------------------------------------------------------
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//////////////////////////////////////////////////////////////////////
// ImageDataObject.h: Impementation for IDataObject Interface to be used
//                       in inserting bitmap to the RichEdit Control.
//
// Author : Hani Atassi  (atassi@arabteam2000.com)
//
// How to use : Just call the static member InsertBitmap with
//              the appropriate parrameters.
//
// Known bugs :
//
//
//////////////////////////////////////////////////////////////////////
 
class CImageDataObject : IDataObject
{
public:
    // This static fumction accepts those parameters:
    // IRichEditOle* : a pointer to IRochEditOle interface for the RichEdit Control
    // HBITMAP : the bitmap handle.
    //
    // After calling the function, it inserts the image in the current
    //    position of the RichEdit
    //
    static void InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap);
    //static void InsertBitmap(LPRICHEDITOLE pRichEditOle, HBITMAP hBitmap);
private:
    ULONG   m_ulRefCnt;
    BOOL    m_bRelease;
 
    // The data being bassed to the richedit
    //
    STGMEDIUM m_stgmed;
    FORMATETC m_fromat;
 
public:
    CImageDataObject() : m_ulRefCnt(0)
    {
        m_bRelease = FALSE;
    }
 
    ~CImageDataObject()
    {
        if (m_bRelease)
            ::ReleaseStgMedium(&m_stgmed);
    }
 
    // Methods of the IUnknown interface
    //
    STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
    {
        if (iid == IID_IUnknown || iid == IID_IDataObject)
        {
            *ppvObject = this;
            AddRef();
            return S_OK;
        }
        else
            return E_NOINTERFACE;
    }
    STDMETHOD_(ULONG, AddRef)(void)
    {
        m_ulRefCnt++;
        return m_ulRefCnt;
    }
    STDMETHOD_(ULONG, Release)(void)
    {
        if (--m_ulRefCnt == 0)
        {
            delete this;
        }
 
        return m_ulRefCnt;
    }
 
    // Methods of the IDataObject Interface
    //
    STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium) {
        HANDLE hDst;
        hDst = ::OleDuplicateData(m_stgmed.hBitmap, CF_BITMAP, NULL);
        if (hDst == NULL)
        {
            return E_HANDLE;
        }
 
        pmedium->tymed = TYMED_GDI;
        pmedium->hBitmap = (HBITMAP)hDst;
        pmedium->pUnkForRelease = NULL;
 
        return S_OK;
    }
    STDMETHOD(GetDataHere)(FORMATETC* pformatetc, STGMEDIUM*  pmedium ) {
        return E_NOTIMPL;
    }
    STDMETHOD(QueryGetData)(FORMATETC*  pformatetc ) {
        return E_NOTIMPL;
    }
    STDMETHOD(GetCanonicalFormatEtc)(FORMATETC*  pformatectIn ,FORMATETC* pformatetcOut )   {
        return E_NOTIMPL;
    }
    STDMETHOD(SetData)(FORMATETC* pformatetc , STGMEDIUM*  pmedium , BOOL  fRelease ) {
        m_fromat = *pformatetc;
        m_stgmed = *pmedium;
 
        return S_OK;
    }
    STDMETHOD(EnumFormatEtc)(DWORD  dwDirection , IEnumFORMATETC**  ppenumFormatEtc ) {
        return E_NOTIMPL;
    }
    STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink,
        DWORD *pdwConnection) {
        return E_NOTIMPL;
    }
    STDMETHOD(DUnadvise)(DWORD dwConnection) {
        return E_NOTIMPL;
    }
    STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise) {
        return E_NOTIMPL;
    }
 
    // Some Other helper functions
    //
    void SetBitmap(HBITMAP hBitmap);
    IOleObject *GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage);
 
};
//------------------------------------------------------------------------------
2
UeArtemis
18 / 18 / 3
Регистрация: 23.09.2011
Сообщений: 205
02.07.2016, 14:30 40
Обнаружил, что RichEditOleCallback ломает контекстное меню.
Решил в лоб:
C++
1
2
3
4
5
6
7
8
STDMETHODIMP TIRichEditOleCallback::GetContextMenu(THIS_ WORD seltype,
    LPOLEOBJECT lpoleobj, CHARRANGE FAR * lpchrg, HMENU FAR * lphmenu)
{
    TPoint point;
    GetCursorPos(&point);
    FRichEdit->PopupMenu->Popup(point.X,point.Y);
    return S_OK; //E_NOTIMPL;
}
Может, есть более правильное решение?
P.S. Так что же у меня с метафайлами?
0
02.07.2016, 14:30
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
02.07.2016, 14:30
Помогаю со студенческими работами здесь

Картинки в RichEdit
Как в RichEdit вставлять картинки не только формата BMP,но и JPG? Может какой-то dcu файлик...

Масштабирование картинки в RichEdit
Можно ли как-то вставить картинку в RichEdit так, чтобы потом изменять размер при помощи мыши как в...

Удаление ссылки из RichEdit после нажатия на нее
Вобщем при нажатии на ссылку она выделяется буквально на миг и после этого становится не выделенной...

Можно ли в RichEdit запихать содержимое Word-файла (текст и картинки)?
Можно ли в RichEdit запихать содержимое ворд файла? (форматированный текст + картинки) Если можно,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru