|
发表于 2004-4-4 19:42:16
|
显示全部楼层
这里是 sandbank 兄弟翻译的第十六章:
第十六章 剪贴板
简单的文本复制和粘贴功能可通过构件如 Gtk::Entry 和 Gtk::TextView 自由使用,但是你可能需要特别的代码来处理你自己的数据格式。例如,一个绘画的程序将需要特别的代码,可以让复制和粘贴在一个视图,或在文档间进行。
Gtk::Clipboard 是单独的。你可以使用 Gtk::Clipboard::get() 得到它和一个实体。
你的应用程序不需要等待剪贴板的操作,特别是用户选择复制,然后选择粘贴的这段时间。许多 Gtk::Clipboard 方法通过 sigc::slots 指定了返回的方法。当 Gtk::Clipboard 准备好了之后,它将会调用这些方法,或是提供要求的数据,或是要求数据。
参考文档
Targets
不同的应用程序含有不同类型的数据,而且他们可让这些数据变为不同的格式。gtkmmm将这些数据类型叫做targets。
例如,gedit能接收和支持 "UTF8_STRING" target,所以你能够从支持这个target的任何程序中粘贴数据到gedit中。或者两个不同的图像编辑程序可支持和接收一些不同的图像格式,它们是以targets形式出现的。只要一个程序能够接收另一个提供的targets中的一个,那么你就可以从一个程序向另一个复制数据。
一个target能以多种二进制格式出现。在这一章,和这些例子中,数据被假定是8位的文本格式。这可以让我们使用XML格式作为剪贴板的数据。然而,这可能对二进制数据如图像是不适合的。Gtk::Clipboard提供了负载,让你需要的话,可以在格式上指定更多的细节。
拖放操作的API使用相同的机制。你将可能在剪贴板和拖放操作中使用相同的数据targets和数据格式。
复制
当用户要求复制一些数据时,你将要告诉剪贴板什么target是有效的,并提供回调函数,让它用来取得数据。这样的话,你需要存储数据的一个副本,当剪贴板调用回调方法时,用来作为对粘贴操作的回应。
例如:
[PHP]
Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
//Targets:
std::list<Gtk::TargetEntry> listTargets;
listTargets.push_back( Gtk::TargetEntry("example_custom_target") );
listTargets.push_back( Gtk::TargetEntry("UTF8_STRING") );
refClipboard->set( listTargets,
sigc::mem_fun(*this, &ExampleWindow:n_clipboard_get),
sigc::mem_fun(*this, &ExampleWindow:n_clipboard_clear) );
[/PHP]
当用户选择粘贴数据时,你的回调函数将提供存储的数据。例如:
[PHP]
void ExampleWindow:n_clipboard_get(Gtk::SelectionData& selection_data, guint info)
{
const Glib::ustring& target = selection_data.get_target();
if(target == "example_custom_target")
selection_data.set("example_custom_target", m_ClipboardStore);
}
[/PHP]
下面的例子ideal能够支持多于一个的剪贴板target。
当剪贴板用其它的东西代替了它的数据时,这个清除回调函数让你释放内存,它是你存储的数据占用的。
粘贴
当用户从剪贴板获取要粘贴的数据时,你需要指定一个格式,并提供一个回调函数,它将和实际的数据一起被调用。例如:
[PHP]
refClipboard->request_contents("example_custom_target", sigc::mem_fun(*this, &ExampleWindow:n_clipboard_received) );
[/PHP]
下面是回调函数的一个例子:
[PHP]
void ExampleWindow:n_clipboard_received(const Gtk::SelectionData& selection_data)
{
Glib::ustring clipboard_data = selection_data.get_data_as_text();
//Do something with the pasted data.
//对粘贴的数据做相应的操作
}
[/PHP]
发现一个有效的target
要从剪贴板上找出当前什么target是对粘贴有效的,请调用方法 request_methods() ,并指定一个和这个信息一起被调用的方法。例如:
[PHP]
refClipboard->request_targets( sigc::mem_fun(*this, &ExampleWindow:n_clipboard_received_targets) );
[/PHP]
在你的回调函数中,同有效的targets(使用他们可以让你的应用程序支持粘贴操作)的一个清单做个比较。你可以启用和禁用一个粘贴菜单项,这决定于粘贴操作当前是否有效。例如:
[PHP]
void ExampleWindow:n_clipboard_received_targets(const Gtk::SelectionData& selection_data)
{
bool bPasteIsPossible = false;
//Get the list of available clipboard targets:
//得到有效剪贴板targets的清单
typedef std::list<Glib::ustring> type_listTargets;
type_listTargets targets = selection_data.get_targets();
//and see if one is suitable:
//检查它是否合适
for(type_listTargets::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
{
if(*iter == "example_custom_target")
bPasteIsPossible = true;
}
//Do something, depending on whether bPasteIsPossible is true.
//做些事情,决定于bPasteIsPossible是否为真。
}
[/PHP]
例子
simple
这个例子允许复制和粘贴应用程序的特别的数据,使用的是标准的文本target。因为这只是一个例子,它并不太完美,当剪贴板的数据作为一种特别的类型时,它并不能识别出。
图 16.1 simple
源代码
文件: examplewindow.h
[PHP]
#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
public:
ExampleWindow();
virtual ~ExampleWindow();
protected:
//Signal handlers:
//信号处理函数
virtual void on_button_copy();
virtual void on_button_paste();
virtual void on_clipboard_text_received(const Glib::ustring& text);
//Child widgets:
//子构件
Gtk::VBox m_VBox;
Gtk:abel m_Label;
Gtk::Table m_Table;
Gtk::ToggleButton m_ButtonA1, m_ButtonA2, m_ButtonB1, m_ButtonB2;
Gtk::HButtonBox m_ButtonBox;
Gtk::Button m_Button_Copy, m_Button_Paste;
};
#endif //GTKMM_EXAMPLEWINDOW_H
[/PHP]
文件: examplewindow.cc
[PHP]
#include "examplewindow.h"
ExampleWindow::ExampleWindow()
: m_Label("Select cells in the table, click Copy, then open a second instance of this example to try pasting the copied data."),
m_Table(2, 2, true),
m_ButtonA1("A1"), m_ButtonA2("A2"), m_ButtonB1("B1"), m_ButtonB2("B2"),
m_Button_Copy(Gtk::Stock::COPY), m_Button_Paste(Gtk::Stock:ASTE)
{
set_title("Gtk::Clipboard example");
set_border_width(12);
add(m_VBox);
m_VBox.pack_start(m_Label, Gtk:ACK_SHRINK);
//Fill Table:
//填充表
m_VBox.pack_start(m_Table);
m_Table.attach(m_ButtonA1, 0, 1, 0, 1);
m_Table.attach(m_ButtonA2, 1, 2, 0, 1);
m_Table.attach(m_ButtonB1, 0, 1, 1, 2);
m_Table.attach(m_ButtonB2, 1, 2, 1, 2);
//Add ButtonBox to bottom:
//在底部增加ButtonBox
m_VBox.pack_start(m_ButtonBox, Gtk:ACK_SHRINK);
m_VBox.set_spacing(6);
//Fill ButtonBox:
//填充ButtonBox
m_ButtonBox.set_layout(Gtk::BUTTONBOX_END);
m_ButtonBox.pack_start(m_Button_Copy, Gtk:ACK_SHRINK);
m_Button_Copy.signal_clicked().connect( sigc::mem_fun(*this, &ExampleWindow:n_button_copy) );
m_ButtonBox.pack_start(m_Button_Paste, Gtk:ACK_SHRINK);
m_Button_Paste.signal_clicked().connect( sigc::mem_fun(*this, &ExampleWindow:n_button_paste) );
show_all_children();
}
ExampleWindow::~ExampleWindow()
{
}
void ExampleWindow:n_button_copy()
{
//Build a string representation of the stuff to be copied:
//建立一个要被复制的字符串的副本
//Ideally you would use XML, with an XML parser here:
//理想情况下,你会用到XML,这里使用了一个XML分析器
Glib::ustring strData;
strData += m_ButtonA1.get_active() ? "1" : "0";
strData += m_ButtonA2.get_active() ? "1" : "0";
strData += m_ButtonB1.get_active() ? "1" : "0";
strData += m_ButtonB2.get_active() ? "1" : "0";
Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
refClipboard->set_text(strData);
}
void ExampleWindow::on_button_paste()
{
//Tell the clipboard to call our method when it is ready:
//告诉剪贴板准备好了之后调用我们的方法
Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
refClipboard->request_text( sigc::mem_fun(*this, &ExampleWindow::on_clipboard_text_received) );
}
void ExampleWindow::on_clipboard_text_received(const Glib::ustring& text)
{
//See comment in on_button_copy() about this silly clipboard format.
//请看on_button_copy()中关于这个剪贴板格式的注释。
if(text.size() >= 4)
{
m_ButtonA1.set_active( text[0] == '1' );
m_ButtonA2.set_active( text[1] == '1' );
m_ButtonB1.set_active( text[2] == '1' );
m_ButtonB2.set_active( text[3] == '1' );
}
}
[/PHP]
文件: main.cc
[PHP]
#include <gtkmm/main.h>
#include "examplewindow.h"
int main(int argc, char *argv[])
{
Gtk::Main kit(argc, argv);
ExampleWindow window;
Gtk::Main::run(window);
//Shows the window and returns when it is closed.
//显示窗体,当它关闭时返回。
return 0;
}
[/PHP]
Ideal
这就像是例子simple, 但是它:
1.定义了一个自定义剪贴板target, 但是这个target的格式仍是文本。
2.它支持粘贴两个target - 自定义的和一个文本的,文本的创建了一个自定义数据的专门的文本替代品。
3.它使用 request_targets() ,并禁用Paste按钮(如果它不能使用剪贴板中的任何东西)。
图 16.2. Ideal
源代码
文件: examplewindow.h
[PHP]
#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
public:
ExampleWindow();
virtual ~ExampleWindow();
protected:
//Signal handlers:
//信号处理函数
virtual void on_button_copy();
virtual void on_button_paste();
virtual void on_clipboard_get(Gtk::SelectionData& selection_data, guint info);
virtual void on_clipboard_clear();
virtual void on_clipboard_received(const Gtk::SelectionData& selection_data);
virtual void on_clipboard_received_targets(const Glib::StringArrayHandle& targets_array);
virtual void update_paste_status();
//Disable the paste button if there is nothing to paste.
//如果没有要粘贴的东西,则禁用粘贴按钮。
//Child widgets:
//子构件
Gtk::VBox m_VBox;
Gtk:abel m_Label;
Gtk::Table m_Table;
Gtk::ToggleButton m_ButtonA1, m_ButtonA2, m_ButtonB1, m_ButtonB2;
Gtk::HButtonBox m_ButtonBox;
Gtk::Button m_Button_Copy, m_Button_Paste;
Glib::ustring m_ClipboardStore;
//Keep copied stuff here, until it is pasted. This could be a big complex data structure.
//保持要复制的东西在这里,直到它被粘贴了。这可能是一个很大很复杂的数据结构。
};
#endif //GTKMM_EXAMPLEWINDOW_H
[PHP]
文件: examplewindow.cc
[PHP]
#include "examplewindow.h"
#include <algorithm>
namespace
{
const char example_target_custom[] = "gtkmmclipboardexample";
const char example_target_text[] = "UTF8_STRING";
} // anonymous namespace //匿名名字空间
ExampleWindow::ExampleWindow()
: m_Label("Select cells in the table, click Copy, then open a second instance "
"of this example to try pasting the copied data.\nOr try pasting the "
"text representation into gedit."),
m_Table(2, 2, true),
m_ButtonA1("A1"), m_ButtonA2("A2"), m_ButtonB1("B1"), m_ButtonB2("B2"),
m_Button_Copy(Gtk::Stock::COPY), m_Button_Paste(Gtk::Stock:ASTE)
{
set_title("Gtk::Clipboard example");
set_border_width(12);
add(m_VBox);
m_VBox.pack_start(m_Label, Gtk:ACK_SHRINK);
//Fill Table:
//填充表
m_VBox.pack_start(m_Table);
m_Table.attach(m_ButtonA1, 0, 1, 0, 1);
m_Table.attach(m_ButtonA2, 1, 2, 0, 1);
m_Table.attach(m_ButtonB1, 0, 1, 1, 2);
m_Table.attach(m_ButtonB2, 1, 2, 1, 2);
//Add ButtonBox to bottom:
//在底部增加ButtonBox
m_VBox.pack_start(m_ButtonBox, Gtk:ACK_SHRINK);
m_VBox.set_spacing(6);
//Fill ButtonBox:
//填充ButtonBox
m_ButtonBox.set_layout(Gtk::BUTTONBOX_END);
m_ButtonBox.pack_start(m_Button_Copy, Gtk:ACK_SHRINK);
m_Button_Copy.signal_clicked().connect( sigc::mem_fun(*this, &ExampleWindow::on_button_copy) );
m_ButtonBox.pack_start(m_Button_Paste, Gtk:ACK_SHRINK);
m_Button_Paste.signal_clicked().connect( sigc::mem_fun(*this, &ExampleWindow::on_button_paste) );
show_all_children();
update_paste_status();
}
ExampleWindow::~ExampleWindow()
{
}
void ExampleWindow::on_button_copy()
{
//Build a string representation of the stuff to be copied:
//建立一个要被复制的字符串的副本
//Ideally you would use XML, with an XML parser here:
//理想情况下,你会用到XML,这里使用了一个XML分析器
Glib::ustring strData;
strData += m_ButtonA1.get_active() ? "1" : "0";
strData += m_ButtonA2.get_active() ? "1" : "0";
strData += m_ButtonB1.get_active() ? "1" : "0";
strData += m_ButtonB2.get_active() ? "1" : "0";
//Store the copied data until it is pasted:
//存储数据直到它被粘贴
m_ClipboardStore = strData;
Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
//Targets:
std::list<Gtk::TargetEntry> listTargets;
listTargets.push_back( Gtk::TargetEntry(example_target_custom) );
listTargets.push_back( Gtk::TargetEntry(example_target_text) );
refClipboard->set( listTargets, sigc::mem_fun(*this, &ExampleWindow::on_clipboard_get), sigc::mem_fun(*this, &ExampleWindow::on_clipboard_clear) );
update_paste_status();
}
void ExampleWindow::on_button_paste()
{
//Tell the clipboard to call our method when it is ready:
//告诉剪贴板准备好了后,调用我们的方法。
Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
refClipboard->request_contents(example_target_custom, sigc::mem_fun(*this, &ExampleWindow::on_clipboard_received) );
update_paste_status();
}
void ExampleWindow::on_clipboard_get(Gtk::SelectionData& selection_data, guint)
{
//info is meant to indicate the target, but it seems to be always 0,
//so we use the selection_data's target instead.
//到了指出target的时候了,但它看起来总是0,
//所以我们使用 selection_data 的 target 代替。
const std::string target = selection_data.get_target();
if(target == example_target_custom)
{
// This set() override uses an 8-bit text format for the data.
//这个set()对数据使用了8位文本格式。
selection_data.set(example_target_custom, m_ClipboardStore);
}
else if(target == example_target_text)
{
//Build some arbitrary text representation of the data,
//so that people see something when they paste into a text editor:
//建立数据的专有的文本格式替代品,
//所以当用户粘贴它们到文本编辑器中时,会看到一些东西。
Glib::ustring text_representation;
text_representation += m_ButtonA1.get_active() ? "A1, " : "";
text_representation += m_ButtonA2.get_active() ? "A2, " : "";
text_representation += m_ButtonB1.get_active() ? "B1, " : "";
text_representation += m_ButtonB2.get_active() ? "B2, " : "";
selection_data.set_text(text_representation);
}
else
{
g_warning("ExampleWindow::on_clipboard_get(): Unexpected clipboard target format.");
}
}
void ExampleWindow::on_clipboard_clear()
{
//This isn't really necessary. I guess it might save memory.
//这其实不太需要,我猜它可能是节省内存。
m_ClipboardStore.clear();
}
void ExampleWindow::on_clipboard_received(const Gtk::SelectionData& selection_data)
{
const std::string target = selection_data.get_target();
if(target == example_target_custom)
//It should always be this, because that' what we asked for when calling request_contents().
//它必须总这样,因为它是我们调用request_contents()时需要的。
{
Glib::ustring clipboard_data = selection_data.get_data_as_string();
//See comment in on_button_copy() about this silly clipboard format.
//请看on_button_copy()中关于这个剪贴板格式的注释。
if(clipboard_data.size() >= 4)
{
m_ButtonA1.set_active( clipboard_data[0] == '1' );
m_ButtonA2.set_active( clipboard_data[1] == '1' );
m_ButtonB1.set_active( clipboard_data[2] == '1' );
m_ButtonB2.set_active( clipboard_data[3] == '1' );
}
}
}
void ExampleWindow::update_paste_status()
{
//Disable the paste button if there is nothing to paste.
//如果没有要粘贴的东西,则禁用粘贴按钮。
Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
//Discover what targets are available:
//发现什么targets是有效的。
refClipboard->request_targets( sigc::mem_fun(*this, &ExampleWindow::on_clipboard_received_targets) );
}
void ExampleWindow::on_clipboard_received_targets(const Glib::StringArrayHandle& targets_array)
{
// Get the list of available clipboard targets:
//得到有效剪贴板targets的清单。
const std::list<std::string> targets (targets_array);
const bool bPasteIsPossible =
std::find(targets.begin(), targets.end(), example_target_custom) != targets.end();
// Enable/Disable the Paste button appropriately:
// 相应地 启用/禁用 按钮Paste。
m_Button_Paste.set_sensitive(bPasteIsPossible);
}
[/PHP]
文件: main.cc
[PHP]
#include <gtkmm/main.h>
#include "examplewindow.h"
int main(int argc, char *argv[])
{
Gtk::Main kit(argc, argv);
ExampleWindow window;
Gtk::Main::run(window);
//Shows the window and returns when it is closed.
//显示窗体,当它关闭时返回。
return 0;
}
[/PHP] |
|