12
返回列表 发新帖
楼主: Sky-Tiger

Open source Java projects: JFXtras

[复制链接]
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
11#
 楼主| 发表于 2009-2-27 22:37 | 只看该作者
Listing 4. The Help class from a TextSrch2 project's Main.fx file

class Help
{
    function showHelp (owner: Stage): Void
    {
        def helpText = "<html>"
                       "Welcome to Text Search!<br><br>"
                       "Enter the search text in the text field.<br>"
                       "Click <b>Search</b> to initiate the search.<br>"
                       "Click <b>Stop</b> to interrupt a search.<br>"
                       "Click <b>Help</b> to display this help.<br>"
                       "<br>"
                       "The paths of all files that contain<br>"
                       "the search text appear in the list."
                       "</html>";

        var dialogRef: JFXDialog;
        dialogRef = JFXDialog
        {
            title: "Text Search Help"

            owner: owner
            modal: true
            packed: true
            resizable: false

            scene: Scene
            {
                content: VBox
                {
                    content:
                    [
                        SwingLabel
                        {
                            text: helpText
                        }
                        SwingButton
                        {
                            action: function (): Void
                            {
                                dialogRef.close ()
                            }

                            text: "OK"
                        }
                    ]

                    spacing: 10
                }
            }
        }
    }
}

Listing 4 assigns an owner to the owner attribute, specifies a modal window by assigning true to modal, and also assigns true to packed so that the window's contents will just fit into the window. The listing also assigns false to the inherited resizable attribute to prevent the dialog box window from being resized. (The components are not repacked.)

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
12#
 楼主| 发表于 2009-2-27 22:40 | 只看该作者
In response to being clicked, the Help button's action function executes Help {}.showHelp (stageRef) to display the dialog box, whose contents appear in Figure 4.
Figure 4. The text-search window and dialog box are initially centered on the screen. (Click to enlarge.)

osjp-jfxtras-figure4_small.jpg (19.96 KB, 下载次数: 10)

osjp-jfxtras-figure4_small.jpg

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
13#
 楼主| 发表于 2009-2-27 22:40 | 只看该作者
Grid layout

Apart from HBox and VBox, JavaFX 1.0 is lacking in layout classes. Once again, JFXtras comes to the rescue by providing the org.jfxtras.scene.layout.Grid class (for achieving form-based layouts) and its org.jfxtras.scene.layout.Cell, org.jfxtras.scene.layout.GridConstraints, org.jfxtras.scene.layout.Row, and other helper classes.

Grid's attributes include:

    * border (of type Number) specifies the size (in pixels) of the empty and transparent border that surrounds the grid. This attribute defaults to 3.0.
    * hgap (of type Number) specifies the width (in pixels) of empty space between adjacent horizontal cells. This attribute defaults to 3.0.
    * rows (of type Row[]) specifies the rows of nodes that are laid out by the grid.
    * vgap (of type Number) specifies the height (in pixels) of empty space between adjacent vertical cells. This attribute defaults to 3.0.

The Row class provides a single attribute, cells (of type Object[]), which contains the nodes to be laid out in a row. Each entry in this sequence is either a JavaFX node (such as an instance of the javafx.scene.text.Text or javafx.scene.shape.Circle class) or a Cell instance that wraps a node for additional layout control. The Cell class wraps a node (via its content attribute, of type Node) to provide extra control over how the node is positioned and oriented in the grid. This control includes alignment, span, grow, and the ability to override javafx.scene.layout.Resizable properties. Some of Cell's attributes are:

    * halign (of type org.jfxtras.scene.layout.HorizontalAlignment) specifies the horizontal alignment of the cell's contents. This attribute is one of GridConstraints.CENTER (horizontally align to the center of the container), GridConstraints.HFILL (horizontally fill the container with the cell contents), GridConstraints.LEFT (horizontally align to the left of the container), or GridConstraints.RIGHT (horizontally align to the right of the container).
    * hgrow (of type org.jfxtras.scene.layout.Grow) specifies the priority for allocating unused horizontal space. This attribute is one of Grow.ALWAYS (cell always tries to grow, sharing unused space equally with other cells whose hgrow attribute is set to Grow.ALWAYS), Grow.NEVER (don't grow horizontally -- the default), and Grow.SOMETIMES (cell tries to grow, and gets an equal share of unused space if there are no other cells whose hgrow attribute is set to Grow.ALWAYS).
    * hspan (of type Integer) specifies the number of columns occupied by this cell.
    * valign (of type org.jfxtras.scene.layout.VerticalAlignment) specifies the vertical alignment of the cell's contents. This attribute is one of GridConstraints.BASELINE (vertically align the portion above the baseline of the cell to the center of the container), GridConstraints.BOTTOM (vertically align to the bottom of the container), GridConstraints.MIDDLE (vertically align to the center of the container), GridConstraints.TOP (vertically align to the top of the container), and GridConstraints.VFILL (vertically fill the container with the cell contents).
    * vgrow (of type Grow) specifies the priority for allocating unused space vertically. It takes the same values and default as hgrow.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
14#
 楼主| 发表于 2009-2-27 22:40 | 只看该作者
I've created a TextSrch3 NetBeans project (as an extension to the previous TextSrch2 project) that demonstrates Grid and related classes. Listing 5 excerpts this project's Help class.
Listing 5. The Help class from a TextSrch3 project's Main.fx file

class Help
{
    function showHelp (owner: Stage): Void
    {
        def helpText = "<html>"
                       "Welcome to Text Search!<br><br>"
                       "Enter the search text in the text field.<br>"
                       "Click <b>Search</b> to initiate the search.<br>"
                       "Click <b>Stop</b> to interrupt a search.<br>"
                       "Click <b>Help</b> to display this help.<br>"
                       "<br>"
                       "The paths of all files that contain<br>"
                       "the search text appear in the list."
                       "</html>";

        var dialogRef: JFXDialog;
        dialogRef = JFXDialog
        {
            title: "Text Search Help"

            owner: owner
            modal: true
            packed: true
            resizable: false

            scene: Scene
            {
                content: Grid
                {
                    border: 15

                    rows:
                    [
                        Row
                        {
                            cells: SwingLabel
                            {
                                text: helpText
                            }
                        }
                        Row
                        {
                            cells: Cell
                            {
                                content: SwingButton
                                {
                                    action: function (): Void
                                    {
                                        dialogRef.close ()
                                    }

                                    text: "OK"
                                }

                                horizontalAlignment: GridConstraints.CENTER
                            }
                        }
                    ]

                    vgap: 10
                }
            }
        }
    }
}

Listing 5 initializes Grid's border attribute to specify an empty border around the dialog box's content. It also initializes Grid's vgap attribute to place some empty space between the text and the button. The rows attribute is populated with two Rows, with the second row consisting of a single Cell that centers its wrapped SwingButton.

Figure 5 shows the visually improved dialog box.

The grid simplifies component centering, provides a border, and provides a vertical gap between the text and the button.
Figure 5. The grid simplifies component centering, provides a border, and provides a vertical gap between the text and the button. (Click to enlarge.)

osjp-jfxtras-figure5_small.jpg (19.29 KB, 下载次数: 5)

osjp-jfxtras-figure5_small.jpg

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
15#
 楼主| 发表于 2009-2-27 22:40 | 只看该作者
Language-oriented classes

The org.jfxtras.lang package provides JFXObject and JFXException classes for (respectively) providing base functionality that is generally useful to all JavaFX objects (such as returning an object's class type), and for supporting the declarative construction of runtime exceptions (that is, classes extending java.lang.RuntimeException). Listing 6 demonstrates these classes.
Listing 6. Main.fx for a LangDemo project

/*
* Main.fx
*/

package langdemo;

import org.jfxtras.lang.JFXException;
import org.jfxtras.lang.JFXObject;

class NegativeBalanceException extends JFXException
{
}

class Account extends JFXObject
{
    var balance: Number on replace oldValue = newValue
    {
        if (newValue < 0.0)
        {
            balance = oldValue;
            throw NegativeBalanceException
            {
                message: "attempt to set balance to {newValue}"
            }
        }
    }

    function deposit (amount: Number): Void
    {
        balance += amount;
    }

    function withdraw (amount: Number): Void
    {
        balance -= amount;
    }

    override function toString (): String
    {
        "balance = {balance}"
    }
}

def acct = Account { balance: 1000.0 }
println (acct);
println (acct.getJFXClass ());
acct.deposit (1000.0);
println (acct);
acct.withdraw (100.0);
println (acct);
acct.withdraw (1901.0)

Listing 6 invokes JFXObject's public getJFXClass(): javafx.reflect.FXClassType function to return the acct object's class type, which subsequently outputs. This listing also subclasses JFXException to provide a suitably named exception class, and declaratively initializes an instance of this class prior to throwing the exception when an attempt is made to withdraw too much money.

This script generates the following output:

balance = 1000.0
class langdemo.Main.Account
balance = 2000.0
balance = 1900.0
Exception in trigger:
langdemo.Main$NegativeBalanceException: attempt to set balance to -1.0
        at langdemo.Main$Account$1.onChange(Main.fx:21)

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
16#
 楼主| 发表于 2009-2-27 22:41 | 只看该作者
Native menus

JFXtras provides, via org.jfxtras.menu's six classes, declarative access to AWT-based menus for integrating pop-up menus into your applications. You can use the classes below to create pop-up menus for use with the system tray, to create and show context-sensitive pop-up menus for different nodes, and so on:

    * NativePopupMenu provides a JavaFX wrapper for the java.awt.PopupMenu class. This class provides a parent attribute (of type java.awt.Component) that identifies the pop-up menu's AWT component. Invoke this class's public show(origin: java.awt.Component, x: Integer, y: Integer): Void function to show the pop-up menu at the specified coordinates relative to the origin component.
    * NativeMenu provides a JavaFX wrapper for the java.awt.Menu class and serves as NativePopupMenu's parent. This class provides an items attribute (of type NativeMenuEntry[]) that identifies the menu entries associated with this menu.
    * NativeMenuEntry serves as the base class for NativeMenuItem.
    * NativeMenuItem provides a JavaFX wrapper for the java.awt.MenuItem class and serves as the parent of the NativeMenu class (and also the NativeCheckboxMenuItem class). This class provides an action attribute (of type function(): Void) for specifying the function that's executed when this menu item is clicked. The class also provides a text attribute (of type String) that specifies the menu item's displayed text.
    * NativeCheckboxMenuItem provides a JavaFX wrapper for the java.awt.CheckboxMenuItem class. This class provides a selected attribute (of type Boolean) that specifies this menu item's checked state.

I've created a TextSrch4 NetBeans project (as an extension to the previous TextSrch3 project) that demonstrates NativePopupMenu and NativeMenuItem. Listing 7 excerpts this project's createMenu() function.
Listing 7. The createMenu() function from a TextSrch4 project's Main.fx file

function createMenu (parent: Component): NativePopupMenu
{
    NativePopupMenu
    {
        items:
        [
            NativeMenuItem
            {
                action: function (): Void
                {
                    Help {}.showHelp (stageRef)
                }

                text: "Help..."
            }
        ]

        parent: parent
    }
}

Listing 7's createMenu() function constructs and returns a pop-up menu with a single Help... menu item (as an alternative to a Help button) for activating the help dialog box. Whenever this menu item is clicked, its action function instantiates the Help class and invokes that class's showHelp() function to present the help dialog box shown previously in Figure 5.

This menu is created via def menu = createMenu (stageRef.getWindow ());, which appears in the script after the stage's declaration. This positioning is necessary to ensure that the stage (an instance of JFXStage) is visible so that its public getWindow(): java.awt.Window function can return a non-null AWT parent for the native pop-up menu.

To ensure that the pop-up menu can be triggered from anywhere on the scene, I inserted a transparent rectangle behind all other scene content. As Listing 8 shows, I then assigned functions to this Rectangle object's onMousePressed and onMouseReleased attributes to show the pop-up menu whenever they detect a menu-trigger.
Listing 8. The menu-trigger detection and display logic from a TextSrch4 project's Main.fx file

onMousePressed: function (me: MouseEvent): Void
{
    if (me.popupTrigger)
        menu.show (stageRef.getWindow (), me.x, me.y)
}

onMouseReleased: function (me: MouseEvent): Void
{
    if (me.popupTrigger)
        menu.show (stageRef.getWindow (), me.x, me.y)
}

Because pop-up menus are triggered differently on different platforms, isPopupTrigger is checked in both of the functions assigned to onMousePressed and mouseReleased, to ensure proper cross-platform behavior.

Figure 6 reveals the pop-up menu for activating the help dialog box.

Right-click (on Windows platforms, if the left and right mouse buttons haven't been reversed) to activate the pop-up menu.
Figure 6. Right-click (on Windows platforms, if the left and right mouse buttons haven't been reversed) to activate the pop-up menu. (Click to enlarge.)
More advanced menu example

Stephen Chin demonstrates the native menu classes in his  DockDialog.fx source code, which is part of WidgetFX.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
17#
 楼主| 发表于 2009-2-27 22:41 | 只看该作者
Unit testing

Recognizing the importance of unit testing, JFXtras provides a declarative unit-testing framework that lets you write JavaFX tests in JavaFX. This testing framework is modeled after best-of-class, behavior-driven, and fluent testing patterns to make tests easier to read and maintain. It consists of the following classes, located in the org.jfxtras.test package:

    * Test is the base class for creating declarative, fluent, behavior-driven tests.
    * Assumption describes a condition that must be met before a test can be run.
    * Expectation specifies a declarative assertion that causes a test to fail if it's not true.
    * Expect provides several convenience functions (such as public equalTo(expected: java.lang.Object): Expectation) that return standard Expectations.
    * ExpectationException is thrown when an expectation is not met.
    * TestResults records the number of failed, passed, and skipped tests.

I've created a BasicTests NetBeans project that demonstrates this unit-testing framework in terms of its Test and Expect classes. Listing 9 presents this project's Main.fx script.
Listing 9. Main.fx for a BasicTests project

/*
* Main.fx
*/

package basictests;

import org.jfxtras.test.Expect;
import org.jfxtras.test.Test;

Test
{
     say: "factorialGood should return 24 when passed 4"
     do: function () { factorialGood (4) }
     expect: Expect.equalTo (24)
}
.perform ();

println (" ");

Test
{
     say: "factorialBad should return 24 when passed 4"
     do: function () { factorialBad (4) }
     expect: Expect.equalTo (24)
}
.perform ();

function factorialGood (n: Integer): Integer
{
    if (n == 0) 1 else n*factorialGood (n-1)
}

function factorialBad (n: Integer): Integer
{
    if (n < 0) 1 else n*factorialBad (n-1)
}

Listing 9 tests two functions that return factorials. Each test is established by creating a Test object, assigning appropriate values to Test's say (of type String), do (of type function(): Object), and expect (of type Expectation[]) attributes, and invoking Test's public perform(): Test function to run the test. This function outputs test results after running the test.

The String assigned to say describes what the test should accomplish. The function assigned to do contains the code to be tested. It should return a value that can be checked by the expect clause, which consists of a sequence of Expectations; the test fails if any Expectation is not true. Any exceptions thrown from the function are counted towards a test failure unless defined via Test's expectException attribute.

This script generates the following output:

test: factorialGood should return 24 when passed 4.
Test Results: 1 passed, 0 failed, 0 skipped.
Test run was successful!

test: factorialBad should return 24 when passed 4.
TEST FAILURE:
Expected: equal to "24"
  Actual: 0
Test Results: 0 passed, 1 failed, 0 skipped.
TEST RUN FAILED WITH ERRORS.  See above for cause of failures.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
18#
 楼主| 发表于 2009-2-27 22:41 | 只看该作者
Utilities classes

Finally, JFXtras provides a pair of utilities classes in its org.jfxtras.util package. The GeometryUtil class provides functions for converting between JavaFX and Java versions of the Point2D and Rectangle2D classes, whereas the SequenceUtil class provides the following sequence-oriented functions:

    * public characterSequence(start: java.lang.String, end: java.lang.String): <any>[] generates and returns a sequence of one-character strings, starting with the first character of the start string and ending with the first character of the end string.
    * public concat(seq: java.lang.String[]): java.lang.String concatenates all elements in a sequence of Strings into a single String, which is returned.
    * public fold(ident: Number, seq: Number[], func: com.sun.javafx.functions.Function2): Number performs what is known in functional languages as a left fold operation. This operation consists of passing ident's value and seq's first element to reduce function func, which combines these two inputs into a single output. This output value and seq's second element are passed to func, resulting in a new output value. This output value and seq's third value are passed to func, and so on until there are no elements left in seq. The fold() function returns the final output value. Check out Wikipedia's Fold (higher-order function) entry to learn more about this operation.
    * public fold(ident: Integer, seq: Integer[], func: com.sun.javafx.functions.Function2): Integer is equivalent to the former function, but is typed for Integers.
    * public fold(ident: java.lang.Object, seq: java.lang.Object[], func: com.sun.javafx.functions.Function2): java.lang.Object is equivalent to the former function, but is typed for java.lang.Objects.
    * public join(seq: java.lang.String[], delimiter: java.lang.String): java.lang.String joins all of seq's String elements into a single String, with the specified delimiter appearing between successive Strings. The resulting String is returned.
    * public sum(seq: Number[]): Number adds all elements of a Numbers sequence and returns the total.
    * public sum(seq: Integer[]): Integer adds all elements of an Integers sequence and returns the total.

Listing 1 presented an example of SequenceUtil's characterSequence() function. Listing 10 provides another example of this function, and also demonstrates most of the other functions.
Listing 10. Main.fx for a UtilDemo project

/*
* Main.fx
*/

package utildemo;

import org.jfxtras.util.SequenceUtil;

def letters = SequenceUtil.characterSequence ("dog", "bone");
println (letters);
println (SequenceUtil.concat (letters));
println (SequenceUtil.join (letters, ", "));

def grades = [ 69, 23, 46, 58 ];
println ("Average = {SequenceUtil.sum (grades)/sizeof grades}");

// What is the sum of the series 1+1/2+1/4+1/8+1/16+... (forever)?

var numbers: Number[];
for (i in [0..100])
     insert 1.0/java.lang.Math.pow (2, i) into numbers;
println ("Sum = {SequenceUtil.sum (numbers)}");

// Use a fold function to calculate 5! (factorial).

println (SequenceUtil.fold (1, [2, 3, 4, 5], multiply));

function multiply (a: Integer, b: Integer): Integer
{
    a*b
}

This script generates the following output:

[ d, c, b ]
dcb
d, c, b
Average = 49
Sum = 2.0
120

In conclusion

JFXtras offers considerable value for your JavaFX projects; I wouldn't be surprised to see JFXtras features appearing in future releases of JavaFX. Now that you've finished this article's brief tour of JFXtras 0.2, I recommend digging deeper into its unit-testing framework and other features. And don't forget to check out JFXtras 0.3, which supports MiGLayout and is compatible with JavaFX 1.1!

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表