📄 waprender.java
字号:
addElement(element);
element.setX(curRenderX);
element.setY(curRenderY);
// 加载图片
Image img = browser.loadImage(src);
if(img!=null){
element.setImage(img);
if(img.getHeight() > curLineMaxHeight){
curLineMaxHeight = img.getHeight() + 1;
}
curRenderX += img.getWidth();
}
}
/**
* Input标记,主要包括文本框,密码框,提交按钮等<br>
* <br>
* 不可嵌套,不可递归
* <br>
* @param e
* @param tag
* @param css
*/
private void dealTag_Input(Enumeration e,Tag tag,Css css){
// <input name="word" size="20" maxlength="128" value="" emptyok="true" />
// <input type="password" name="passWord" size="10" maxlength="10"/>
// <input type="text" name="ss" title="ss" value="" emptyok="true" maxlength="100" size="5" format="*M" tabindex="1" />
// <input type="hidden" name="method" value="signonUser"/>
String type = tag.getParm("type");
String name = tag.getParm("name");
String size = tag.getParm("size");
String maxLength = tag.getParm("maxlength");
String value = tag.getParm("value");
// input元素也是可以选择的,假设它为hotspot
HotSpot hotspot = new HotSpot();
Element element = null;
// 默认是text类型的Input
if(type==null || type.equals("")) type = "text";
// 默认size为8
if(size==null || size.equals("")) size = "8";
// 默认maxLength为100
if(maxLength==null || maxLength.equals("")) maxLength="100";
if(name==null || name.equals("")) name = "";
if(value==null || value.equals("")) value = "";
// 文本框和密码框
if(type.equals("text") || type.equals("password")){
Input input = new Input(hotSpotNum,lineNum,
(type.equals("text")?Element.TEXT_INPUT:Element.PASSWORD_INPUT)
,browser);
input.setName(name);
input.setSize(Integer.parseInt(size));
input.setMaxLength(Integer.parseInt(maxLength));
input.setValue(value);
formElements.put(name, input);
element = input;
hotspot.type = type.equals("text")?Element.TEXT_INPUT:Element.PASSWORD_INPUT;
hotspot.obj = input;
hotspot.elementId = elementNum;
if(inForm) tmpFormElement.addElement(element);
}else
// 提交按钮
if(type.equals("submit")){
Button button = new Button(hotSpotNum,lineNum,browser);
button.setValue(value);
button.setAction(tmpFormAction);
button.setMethod(tmpFormMethod);
button.setElement(tmpFormElement);
element = button;
hotspot.type = Element.BUTTON;
hotspot.obj = button;
hotspot.elementId = elementNum;
}else
// 隐藏的文本框,只用于提交数据时产生参数,不加入元素显示队列
if(type.equals("hidden")){
Input input = new Input(hotSpotNum,lineNum,Element.TEXT_INPUT,browser);
input.setName(name);
input.setValue(value);
if(inForm) tmpFormElement.addElement(input);
return;
}
if(element!=null){
// 强制换行
newLine(2, 0);
curLineMaxHeight = element.getHeight();
element.setX(curRenderX);
element.setY(curRenderY);
// 强制换行
newLine(0,0);
addElement(element);
addHotSpot(hotspot);
}
}
/**
* 单选和复选标记,若标记中没有指定multiple属性,则默认为单选 <br>
* -复选: multiple = true <br>
* -单选: multiple = false <br>
* <br>
* 不可嵌套,不可递归
* <br>
* @param e
* @param tag
* @param css
*/
private void dealTag_Select(Enumeration e,Tag tag,Css css){
Object obj = null;
HotSpot hotspot = new HotSpot();
String name = tag.getParm("name");
String multiple = tag.getParm("multiple");
// 不允许名字为空
if(name == null || name.equals("")){
name = "form"+formElements.size();
}
Select select = null;
if(multiple == null || multiple.equals("") || multiple.equals("false")){
// 单选
select = new Select(hotSpotNum,lineNum,Element.SELECT_EXCLUSIVE,browser);
hotspot.type = Element.SELECT_EXCLUSIVE;
}else{
// 复选
select = new Select(hotSpotNum,lineNum,Element.SELECT_MULTIPLE,browser);
hotspot.type = Element.SELECT_MULTIPLE;
}
select.setName(name);
String defaultValue = tag.getParm("value");
if(defaultValue == null) defaultValue = "";
hotspot.elementId = elementNum;
hotspot.obj = select;
String tmpValue = "";
String tmpLabel = "";
// <select multiple="true">
// <option value="htm">option 1</option>
// <option value="xml">option 2</option>
// <option value="wap" selected="true">option 3</option>
// <option value="wap">option 4</option>
// <option value="wap">option 5</option>
// <option value="wap">option 6</option>
// </select>
boolean selected = false;
while(true){
obj = e.nextElement();
curTagId++;
if(obj instanceof Tag){
tag = (Tag)obj;
// 再次遇见select标记且为结束符时,则退出循环
if(tag.getName().equals("select") && tag.getState() == Tag.TAG_CLOSE){
break;
}else if(tag.getName().equals("option")){
if(tag.getState() == Tag.TAG_OPEN){
tmpValue = tag.getParm("value");
String tmp = tag.getParm("selected");
if(tmp!=null && tmp.equals("true")){
selected = true;
}else{
selected = false;
}
}else{
select.addOption(tmpValue, tmpLabel,selected);
}
}
}else{
// option标记中的普通文字作为选项的label处理
tmpLabel = (String)obj;
}
}
if(select!=null){
// 强制换行
newLine(2, 0);
curLineMaxHeight = select.getHeight();
select.setX(curRenderX);
select.setY(curRenderY);
newLine(0,0);
formElements.put(select.getName(),select);
addElement(select);
addHotSpot(hotspot);
if(inForm) tmpFormElement.addElement(select);
}
}
/**
* 当前的处理是否被包括在某超链接中(以便考虑某文字或图片需要加特殊处理:下划线)
*/
private boolean inHyperlinks;
/**
* 超链接标记,里边的内容有文字和图片<br>
* <br>
* 不可嵌套,不可递归
* <br>
* @param e
* @param tag
* @param css
*/
private void dealTag_A(Enumeration e,Tag tag,Css css){
// 获得标记指定的URL
String href = tag.getParm("href");
href = Tools.RepString(href, "'", "");
// 创建一个超链接对象HotSpot
HotSpot hotspot = new HotSpot();
hotspot.elementId = elementNum;
hotspot.url = href;
Object obj = null;
inHyperlinks = true;
while(true){
obj = e.nextElement();
curTagId++;
if(obj instanceof Tag){
tag = (Tag)obj;
// 再次遇见a标记且为结束符时,则退出循环
if(tag.getName().equals("a") && tag.getState() == Tag.TAG_CLOSE){
break;
}
hotspot.type = Element.NORMAL_IMAGE;
// 超链接里边的标记肯定是图片
dealTag_Img(e,tag,css);
}else{
hotspot.type = Element.NORMAL_TEXT;
dealNormalText((String)obj,css);
}
}
inHyperlinks = false;
addHotSpot(hotspot);
}
/**
* 和超链接类似,但用于提交页面中指定的Input内容<br>
* <br>
* 不可嵌套,不可递归
* <br>
* @param e
* @param tag
* @param css
*/
private void dealTag_Anchor(Enumeration e,Tag tag,Css css){
//String title = tag.getParm("title");
Anchor anchor = new Anchor(browser);
// anchor也表现为一个超链接
HotSpot hotspot = new HotSpot();
hotspot.type = Element.ANCHOR;
hotspot.elementId = elementNum;
hotspot.obj = anchor;
Object obj = null;
while(true){
obj = e.nextElement();
curTagId++;
if(obj instanceof Tag){
tag = (Tag)obj;
// 再次遇见anchor标记且为结束符时,则退出循环
if(tag.getName().equals("anchor") && tag.getState() == Tag.TAG_CLOSE){
break;
}else if(tag.getName().equals("go") && tag.getState() == Tag.TAG_OPEN){
String method = tag.getParm("method");
String href = tag.getParm("href");
anchor.setMethod(method);
anchor.setHref(href);
}else if(tag.getName().equals("postfield")){
// <postfield name="ss" value="$(ss)"/>
String name = tag.getParm("name");
Object value = null;
String tmp = tag.getParm("value");
if(tmp!=null && !tmp.equals("")){
if(tmp.charAt(0)=='$'){
// $(ss),要去掉'$'和"()"
tmp = Tools.RepString(tmp, "$", "");
tmp = Tools.RepString(tmp, "(", "");
tmp = Tools.RepString(tmp, ")", "");
value = formElements.get(tmp);
}else{
value = tmp;
}
}else{
value = "";
}
anchor.addPostfield(name, value);
}
}else{
inHyperlinks = true;
dealNormalText((String)obj,css);
inHyperlinks = false;
}
}
addHotSpot(hotspot);
}
/**
* 将文档渲染到屏幕(文档中的内容都已组织成了Element对象)
* @param g
*/
public void render(Graphics g){
// 背景颜色
g.setColor(_css_bgColor);
g.fillRect(0, 0, width, height);
Element element = null;
int i = 0;
// 因为有些图片可能非常大,一屏显示不下,所以
// 显示区域设置为屏幕原点(0,0)以后的一个屏幕高度的位置
// 即(0,-height)处
int startY = curDrawY - height;
startDrawElement = -1;
// 显示主页面
g.setClip(0,0,scrollBarX - 2,browserHeight);
for(;i<elementNum;i++){
element = (Element) elements.elementAt(i);
// 非显示区域内的元素不画
if(element.y >= startY){
// 屏幕内的第一个元素编号保存在startDrawElement中,方便控制文档的上下移动
if(startDrawElement == -1 && element.y >= curDrawY){
startDrawElement = i;
}
// 将当前元素显示屏幕,注意屏幕坐标curDrawY和元素在文档中的坐标的差别
element.draw(element.y - curDrawY, curHyperlinks, g);
// 超出了显示区域,退出
if(element.y + element.getHeight() - curDrawY > (browserHeight + 10)){
break;
}
}
}
// 将最后一个显示的元素保存在lastDrawElement中,方便控制文档的上下移动
lastDrawElement = i;
// 如果页面高度大于屏幕高度,则显示滚动条
if(curRenderY > browserHeight){
drawScroller(g);
}
}
/**
* 画滚动条
* @param g
*/
private void drawScroller(Graphics g){
g.setClip(scrollBarX,scrollBarY,scrollBarWidth,scrollBarHeight);
int scrollerWidth = scrollBarWidth - 2;
int scrollerHeight = 0;
int scrollerDy = 0;
// 计算滚动子的长度,算法思想:
// 假设整个文档渲染后长度类length,屏幕可视区域高度为screen_height,滚动区域长度为scrollBarHeight
// 那么滚子的长度就是屏幕可视区域的高度在文档中所占的比例乘上滚动区域的长度
// (browserHeight / curRenderY * scrollBarHeight)
// 这里 * 10000 是为了放大数值,以防小数点被舍弃
scrollerHeight = ((browserHeight * 10000 / curRenderY) * (scrollBarHeight - 2)) / 10000;
// 如果滚动条太小,则强制为一个字体的高度(滚动子高度的最小值)
if(scrollerHeight < browser.fontHeight) scrollerHeight = browser.fontHeight;
// 计算当前滚动的距离,算法思想:
// 当前已滚动的长度在文档中可滚动区域中所占比例乘上滚动条可滚动区域长度
// a = (curDrawY / (curRenderY - browserHeight))
// dy = a * (scrollBarHeight - 2 - scrollerHeight)
scrollerDy = ((curDrawY * 10000 / (curRenderY - browserHeight)) * (scrollBarHeight - 2 - scrollerHeight)) / 10000;
// 画滚动条
g.setColor(0x444444);
g.fillRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
// 画滚动子
g.setColor(0xA3B2CC);
g.fillRect(scrollBarX + 1,scrollBarY + 1 + scrollerDy,scrollerWidth,scrollerHeight);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -